简体   繁体   English

将powershell脚本的输出绑定到asp.net c#中的gridview

[英]Binding output from powershell script to gridview in asp.net c#

I'm very new to c# and I expect what I'm trying to do is quite simple-ish but I'm not able to find or follow other examples where output from a powershell array populates a gridview for further manipulation / execution of another script.我对 c# 很陌生,我希望我尝试做的事情非常简单,但我无法找到或遵循其他示例,其中 powershell 数组的输出填充了 gridview 以进一步操作/执行另一个脚本。 The process on page load is to run a powershell script, which creates an array of session details which populate a gridview.页面加载的过程是运行一个 powershell 脚本,该脚本创建一个填充 gridview 的会话详细信息数组。 A second script can then be initiated to interact wit that session (eg force a logoff) by way of selection of the gridview row.然后可以启动第二个脚本以通过选择 gridview 行与该会话交互(例如强制注销)。

Using other examples I have managed to initiate the first powershell execution, which throws the data to a form via:使用其他示例,我设法启动了第一个 powershell 执行,它通过以下方式将数据抛出到表单中:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="PowerShellExecution.Default" %>

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
     <div>
           <h1>PowerShell Harness<asp:Label ID="Label1" runat="server" Text="Label" Visible="False"></asp:Label>
           </h1>
           <asp:TextBox ID="ResultBox" TextMode="MultiLine" Width="1000px" Height="400px" runat="server"></asp:TextBox>
    </div>
</asp:Content>

CodeBehind代码隐藏

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Management.Automation;
using System.Text;

namespace PowerShellExecution
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
          // Gets the name if authenticated.
                if (User.Identity.IsAuthenticated)
                    Label1.Text = User.Identity.Name;
                else
                    Label1.Text = "No user identity available.";

            // Clean the Result TextBox
            ResultBox.Text = string.Empty;

            // Initialize PowerShell engine
            var shell = PowerShell.Create();

            // Add the script to the PowerShell object
            // shell.Commands.AddScript(Input.Text);
            // shell.Commands.AddScript("D:\\Local_Scripts\\sessioncall.ps1");
            shell.Commands.AddCommand("c:\\Local_Scripts\\sessioncall.ps1");

            // Add Params
            // shell.Commands.AddParameter(null,User.Identity.Name);
            // shell.Commands.AddParameter("Username", Label1.Text);
            shell.Commands.AddArgument(User.Identity.Name);

            // Execute the script
            var results = shell.Invoke();

            // display results, with BaseObject converted to string
            // Note : use |out-string for console-like output
            if (results.Count > 0)
            {
                // We use a string builder ton create our result text
                var builder = new StringBuilder();

                foreach (var psObject in results)
                {
                    // Convert the Base Object to a string and append it to the string builder.
                    // Add \r\n for line breaks
                    builder.Append(psObject.BaseObject.ToString() + "\r\n");
                }

                // Encode the string in HTML (prevent security issue with 'dangerous' caracters like < >
                ResultBox.Text = Server.HtmlEncode(builder.ToString());
            }

        }
    }
}

Sessioncall.ps1会话调用.ps1

$SessionUser = "$($args[0])"
set-brokersite -AdminAddress UKSite 
$a = @(Get-BrokerSession -BrokeringUserName $SessionUser | Select-Object UserFullName, BrokeringTime, ClientName,DesktopGroupName, sessionstate, uid, machinename,@{Name='ENV';Expression={'UK'}})
#Pull US Sessions into array
Set-brokersite -AdminAddress USSite
$a += @(Get-BrokerSession -BrokeringUserName $SessionUser | Select-Object UserFullName, BrokeringTime, ClientName,DesktopGroupName, sessionstate, uid, machinename,@{Name='ENV';Expression={'US'}})

If ($a -ne $null){
    Write-Output $a | out-string
}
Else {
    Write-Output "No User session! Username was $SessionUser"
}

Currently the output is thrown to the textbox as an out-string.目前,输出作为输出字符串抛出到文本框。 I'm struggling in even how to start to data-bind that array output as rows within a gridview.我什至在如何开始将数组输出数据绑定为 gridview 中的行方面苦苦挣扎。 Just need a little hand-holding to get this started!只需要一点点的手就可以开始!

Thanks in advance!提前致谢! Paul.保罗。

It's been a while since I've dabbled with WebForms, but I found a way to do what you're after...自从我涉足 WebForms 已经有一段时间了,但我找到了一种方法来做你所追求的......

First off, let's change your PowerShell script slightly.首先,让我们稍微更改您的 PowerShell 脚本。 Rather than return a string (which is what | out-string is doing), we can simply return the objects.我们可以简单地返回对象,而不是返回一个字符串(这就是| out-string正在做的事情)。 The shell.Invoke() method in the C# code knows how to extract fully-fledged objects from the output of the script so we don't need to serialize to a string inside the PowerShell script and then try to deserialize that again back to objects inside our C# code. C# 代码中的shell.Invoke()方法知道如何从脚本的输出中提取成熟的对象,因此我们不需要在 PowerShell 脚本中序列化为字符串,然后再尝试将其反序列化为对象在我们的 C# 代码中。

Ignoring your line-of-business logic for a minute, my script simply returns an array of PSCustomObjects and looks like this:暂时忽略您的业务逻辑,我的脚本只是返回一个 PSCustomObjects 数组,如下所示:

MyScript.ps1 MyScript.ps1

write-output @(
    (new-object PSCustomObject -Property ([ordered] @{
         "MyProperty1" = "MyValue1.1"
         "MyProperty2" = "MyValue2.1"
         "MyProperty3" = "MyValue3.1"
    })),
    (new-object PSCustomObject -Property ([ordered] @{
          "MyProperty1" = "MyValue1.2"
          "MyProperty2" = "MyValue2.2"
          "MyProperty3" = "MyValue3.2"
    }))
);

Now, my C# Page_Load method does this:现在,我的 C# Page_Load 方法执行以下操作:

Default.aspx.cs默认.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{

    // Initialize PowerShell engine
    var powershell = PowerShell.Create();

    // Add the script to the PowerShell object
    var script = "c:\\temp\\MyScript.ps1";
    powershell.Commands.AddCommand(script);

    // Execute the script
    var results = powershell.Invoke();

    ...

and results contains a System.Collections.ObjectModel.Collection<PSObject> . results包含一个System.Collections.ObjectModel.Collection<PSObject> We can't databind that directly to a GridView because the properties are tucked away inside key-value pairs in the Properties member of each PSObject , but if we create a new class it's pretty easy to extract the values into something we can databind:我们无法将其直接绑定到 GridView,因为属性隐藏在每个PSObjectProperties成员中的键值对中,但是如果我们创建一个新类,很容易将值提取到我们可以进行数据绑定的内容中:

MyClass.cs MyClass.cs

public class MyClass
{
    public string MyProperty1 { get; set; }
    public string MyProperty2 { get; set; }
    public string MyProperty3 { get; set; }
}

and our Page_Load can convert the PSObjects into instances of this class:我们的 Page_Load 可以将 PSObjects 转换为此类的实例:

Default.aspx.cs默认.aspx.cs

    ...

    var objects = results.Select(
        r => new MyClass
        {
            MyProperty1 = (string)r.Properties["MyProperty1"].Value,
            MyProperty2 = (string)r.Properties["MyProperty2"].Value,
            MyProperty3 = (string)r.Properties["MyProperty3"].Value,
        }
    );

    this.ResultGrid.DataSource = objects;
    this.ResultGrid.DataBind();

}

Then, to display the data you just need a GridView added to your Default.aspx with whatever columns and formatting you want defined:然后,要显示数据,您只需要将 GridView 添加到您的 Default.aspx 中,并使用您想要定义的任何列和格式:

Default.aspx默认.aspx

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
     <div>
           <h1>PowerShell Harness<asp:Label ID="Label1" runat="server" Text="Label" Visible="False"></asp:Label></h1>
            <asp:GridView ID="ResultGrid" runat="server" AutoGenerateColumns="false">
                <Columns>
                    <asp:BoundField DataField="MyProperty1" HeaderText="My Property 1" />
                    <asp:BoundField DataField="MyProperty2" HeaderText="My Property 2"  />
                    <asp:BoundField DataField="MyProperty3" HeaderText="My Property 3"  />
                </Columns>
            </asp:GridView>
    </div>
</asp:Content>

Run that and you should see something like this on the page:运行它,你应该在页面上看到类似这样的内容:

带有从 PowerShell 脚本绑定的 GridView 的 ASP.Net 页面

Note笔记

You might find your Get-BrokerSession cmdlet returns a collection of a specific type of object already rather than PSCustomObject, in which case you could possibly skip the conversion step and databind directly to the results object, so you might have to play with that to see.您可能会发现您的Get-BrokerSession cmdlet 已经返回了特定类型对象的集合,而不是 PSCustomObject,在这种情况下,您可能会跳过转换步骤并将数据绑定直接到results对象,因此您可能必须使用它才能看到. Hopefully the above will give you some pointers if there are any differences.希望上面会给你一些指点,如果任何的差异。

Hope this helps.希望这可以帮助。

Many thanks for the guidance.非常感谢指导。 Gridview now populates. Gridview 现在填充。

    protected void Page_Load(object sender, EventArgs e)
    {
      // Gets the name if authenticated.
            if (User.Identity.IsAuthenticated)
                Label1.Text = User.Identity.Name;
            else
                Label1.Text = "No user identity available.";

        // Clean the Result TextBox

        // Initialize PowerShell engine
        var shell = PowerShell.Create();

        // Add the script to the PowerShell object
        // shell.Commands.AddScript(Input.Text);
        // shell.Commands.AddScript("D:\\Local_Scripts\\sessioncall.ps1");
        shell.Commands.AddCommand("c:\\Local_Scripts\\sessioncall.ps1");

        // Add Params
        // shell.Commands.AddParameter(null,User.Identity.Name);
        // shell.Commands.AddParameter("Username", Label1.Text);
        shell.Commands.AddArgument(User.Identity.Name);

        // Execute the script
        var results = shell.Invoke();

        // display results, with BaseObject converted to string
        // Note : use |out-string for console-like output
        if (results.Count > 0)
        {
            // We use a string builder ton create our result text
            var results2 = shell.Invoke();
            foreach (var psObject in results)
            {
                // Convert the Base Object to a string and append it to the string builder.
                // Add \r\n for line breaks
                var UserFullName = (psObject.Members["UserFullName"]);
                var BrokeringTime = (psObject.Members["BrokeringTime"]);
                var ClientName = (psObject.Members["ClientName"]);
                var DesktopGroupName = (psObject.Members["DesktopGroupName"]);
                var SessionState = (psObject.Members["SessionState"]);
                var Uid = (psObject.Members["Uid"]);
                var MachineName = (psObject.Members["MachineName"]);
                var ENV = (psObject.Members["ENV"]);
                // builder.Append(psObject.BaseObject.ToString() + "\r\n");
            }

            this.ResultGrid.DataSource = results2;
            this.ResultGrid.DataBind();
        }

        }

Returns [![enter image description here][1]][1]返回 [![在此处输入图像描述][1]][1]

However this method throws an exception error when you then define a datakeyname.但是,当您定义 datakeyname 时,此方法会引发异常错误。

<asp:GridView ID="ResultGrid" runat="server" DataKeyNames="uid" AutoGenerateColumns="False" OnSelectedIndexChanged="ResultGrid_SelectedIndexChanged">
                <Columns>
                     <asp:buttonfield buttontype="Button" 
                 commandname="Select"
                 headertext="View" 
                 text="View"/>
                    <asp:BoundField DataField="UserFullName" HeaderText="UserFullName" />
                    <asp:BoundField DataField="BrokeringTime" HeaderText="BrokeringTime"  />
                    <asp:BoundField DataField="ClientName" HeaderText="ClientName"  />
                    <asp:BoundField DataField="DesktopGroupName" HeaderText="DesktopGroupName" />
                    <asp:BoundField DataField="SessionState" HeaderText="SessionState"  />
                    <asp:BoundField DataField="Uid" HeaderText="Uid"  />
                    <asp:BoundField DataField="MachineName" HeaderText="MachineName"  />
                    <asp:BoundField DataField="ENV" HeaderText="ENV"  />
                </Columns>
            </asp:GridView>

code behind背后的代码

 protected void ResultGrid_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Determine the RowIndex of the Row whose Button was clicked.
            //int rowIndex = ((sender as Button).NamingContainer as GridViewRow).RowIndex;
            String key = ResultGrid.SelectedDataKey.Value.ToString();
            //Get the value of column from the DataKeys using the RowIndex.
            //int id = Convert.ToInt32(ResultGrid.DataKeys[rowIndex].Values[01]);
            //  Response.Write("IM_RAA_657x_Date.aspx?Day=" + ResultGrid.SelectedDataKey.Value(0) + "&BusinessCategory=" + ResultGrid.SelectedDataKey.Values(1).ToString())
        }

This throws an exception error at这将引发异常错误

this.ResultGrid.DataBind(); this.ResultGrid.DataBind();

"System.Web.HttpException: 'DataBinding: 'System.Management.Automation.PSObject' does not contain a property with the name 'uid'.'" “System.Web.HttpException: 'DataBinding: 'System.Management.Automation.PSObject' 不包含名为 'uid' 的属性。'”

I'm not clear if the method is now the issue or something outside of that.我不清楚该方法现在是问题还是其他问题。 I'm confused as it must see inside PSObjects correctly in order for the variables to be defined and populate the gridview?!我很困惑,因为它必须正确地看到 PSObjects 内部才能定义变量并填充 gridview?! Hmm.唔。

Wow;哇; OK;好的; I just realised this entire section is ignored!我刚刚意识到整个部分都被忽略了! Case in point;举个例子; it can be commented out!可以注释掉! So clearly adjust the output from the powershell script!所以清楚地调整powershell脚本的输出!

 foreach (var psObject in results)
                {
                    // Convert the Base Object to a string and append it to the string builder.
                    // Add \r\n for line breaks
                    //var UserFullName = (psObject.Members["UserFullName"]);
                    //var BrokeringTime = (psObject.Members["BrokeringTime"]);
                    //var ClientName = (psObject.Members["ClientName"]);
                    //var DesktopGroupName = (psObject.Members["DesktopGroupName"]);
                    //var SessionState = (psObject.Members["SessionState"]);
                    //var Uid = (psObject.Members["Uid"]);
                    //var MachineName = (psObject.Members["MachineName"]);
                    //var ENV = (psObject.Members["ENV"]);
                    // builder.Append(psObject.BaseObject.ToString() + "\r\n");
                }

Forgive me but I'm almost there!原谅我,但我快到了!

r => new MyClass
                        {
                            UserFullName = (string)r.Properties["UserFullName"].Value,
                            BrokeringTime = (DateTime)r.Properties["BrokeringTime"].Value,
                            ClientName = (string)r.Properties["ClientName"].Value,
                            DesktopGroupName = (string)r.Properties["DesktopGroupName"].Value,
                            //SessionState = (string)r.Properties["SessionState"].Value,
                            Uid = (Int64)r.Properties["Uid"].Value,
                            //MachineName = (string)r.Properties["MachineName"].Value,
                            //ENV = (string)r.Properties["ENV"].Value,
                        }
                    );
                this.ResultGrid.DataSource = objects;
                this.ResultGrid.DataBind();
            }

            }

        protected void ResultGrid_SelectedIndexChanged(object sender, EventArgs e)
        {

            Response.Write(ResultGrid.SelectedValue.ToString());

        }
    }

    internal class MyClass
    {
        public string UserFullName { get; set; }
        public DateTime BrokeringTime { get; set; }
        public string ClientName { get; set; }
        public string DesktopGroupName { get; set; }
        public String SessionState { get; set; }
        public Int64 Uid { get; set; }
        public string MachineName { get; set; }
        public string ENV { get; set; }
    }

So I'm now correctly populating the gridview;所以我现在正确地填充了 gridview; Some columns are still being problematic and are not being treated as strings BUT I'm almost there!一些列仍然有问题,没有被视为字符串,但我快到了!

Looks like Get-member type:看起来像 Get-member 类型:

BrokeringTime    NoteProperty datetime BrokeringTime=28/02/2020 06:56:39 
ClientName       NoteProperty string ClientName=clientname           
DesktopGroupName NoteProperty string DesktopGroupName=desktopgroupname
ENV              NoteProperty System.String ENV=UK                       
MachineName      NoteProperty string MachineName=machinename  
SessionState     NoteProperty SessionState SessionState=Active           
Uid              NoteProperty long Uid=12345678                           
UserFullName     NoteProperty string UserFullName=username  

C# Does seem to like system.string. C# 似乎喜欢 system.string。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM