【问题标题】:Binding output from powershell script to gridview in asp.net c#将powershell脚本的输出绑定到asp.net c#中的gridview
【发布时间】:2020-06-11 09:42:57
【问题描述】:

我对 c# 很陌生,我希望我正在尝试做的事情非常简单,但我无法找到或遵循其他示例,其中 powershell 数组的输出填充了网格视图以进行进一步操作/执行另一个脚本。页面加载的过程是运行一个 powershell 脚本,该脚本会创建一个会话详细信息数组,用于填充网格视图。然后可以通过选择 gridview 行来启动第二个脚本以与该会话进行交互(例如强制注销)。

使用其他示例,我设法启动了第一个 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>

代码隐藏

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

$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"
}

当前输出作为输出字符串被抛出到文本框。我什至在如何开始将该数组输出数据绑定为gridview中的行时都在苦苦挣扎。只需稍稍牵手即可开始!

提前致谢! 保罗。

【问题讨论】:

    标签: c# asp.net powershell gridview data-binding


    【解决方案1】:

    自从我涉足 WebForms 以来已经有一段时间了,但我找到了一种方法来做你所追求的......

    首先,让我们稍微更改一下您的 PowerShell 脚本。我们可以简单地返回对象,而不是返回一个字符串(| out-string 正在做的事情)。 C# 代码中的shell.Invoke() 方法知道如何从脚本的输出中提取成熟的对象,因此我们不需要在 PowerShell 脚本中序列化为字符串,然后再尝试将其反序列化回我们内部的对象。 C# 代码。

    暂时忽略您的业务线逻辑,我的脚本只返回一个 PSCustomObjects 数组,如下所示:

    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"
        }))
    );
    

    现在,我的 C# Page_Load 方法执行此操作:

    Default.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();
    
        ...
    

    results 包含System.Collections.ObjectModel.Collection&lt;PSObject&gt;。我们不能将其直接数据绑定到 GridView,因为属性隐藏在每个 Properties 成员的键值对中 PSObject,但是如果我们创建一个新类,很容易将值提取到我们的可以数据绑定:

    MyClass.cs

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

    并且我们的 Page_Load 可以将 PSObject 转换为此类的实例:

    Default.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();
    
    }
    

    然后,要显示数据,您只需在 Default.aspx 中添加一个 GridView,其中包含您想要定义的任何列和格式:

    Default.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>
    

    运行它,你应该会在页面上看到类似这样的内容:

    注意

    您可能会发现您的 Get-BrokerSession cmdlet 已返回特定类型对象的集合,而不是 PSCustomObject,在这种情况下,您可以跳过转换步骤并将数据直接绑定到 results 对象,因此您可能必须玩那个看看。如果存在任何差异,希望以上内容能给您一些指导。

    希望这会有所帮助。

    【讨论】:

    • 非常感谢!这个方法现在对我来说更清楚了,我已经设法继续前进了几个步骤!
    • @darkgen:我建议接受这个答案:发帖者已经付出了巨大的努力来帮助你。
    【解决方案2】:

    非常感谢您的指导。现在填充了 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();
            }
    
            }
    

    返回 [![在此处输入图片描述][1]][1]

    但是,当您随后定义数据键名时,此方法会引发异常错误。

    <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>
    

    后面的代码

     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.ResultGrid.DataBind();

    “System.Web.HttpException: 'DataBinding: 'System.Management.Automation.PSObject' 不包含名为 'uid' 的属性。'”

    我不清楚该方法现在是问题还是其他问题。我很困惑,因为它必须正确查看 PSObjects 内部才能定义变量并填充网格视图?!嗯。

    哇;好的;我刚刚意识到这整个部分都被忽略了!恰当的例子;可以注释掉!所以清楚地调整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");
                    }
    

    原谅我,但我快到了!

    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; }
        }
    

    所以我现在正确地填充了gridview;有些列仍然存在问题,没有被视为字符串,但我快到了!

    看起来像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# 似乎喜欢 system.string。

    【讨论】:

      猜你喜欢
      • 2011-07-08
      • 2018-07-10
      • 1970-01-01
      • 1970-01-01
      • 2011-11-04
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 2018-11-29
      相关资源
      最近更新 更多