格式化托管PowerShell的输出

时间:2010-12-26 16:40:27

标签: c# winforms powershell

我找到了一个C#示例here,它从主机应用程序异步调用PowerShell脚本(在文件夹第6章 - 阅读事件中),并尝试在Windows窗体应用程序中使用它。

我有一个按钮(button1)来启动PowerShell脚本,textBox1是输入脚本而textBox2是显示脚本输出。这是我目前的代码:

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Windows.Forms;

namespace PSTestApp
{

    delegate void SetTextDelegate(string text);

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox2.Text = "";

            Runspace runspace = 
                RunspaceFactory.CreateRunspace();
            runspace.Open();

            Pipeline pipeline = 
                runspace.CreatePipeline(textBox1.Text);

            pipeline.Output.DataReady += 
                new EventHandler(HandleDataReady);
            pipeline.Error.DataReady += 
                new EventHandler(HandleDataReady);

            pipeline.InvokeAsync();
            pipeline.Input.Close();
        }

        private void HandleDataReady(object sender, EventArgs e)
        {
            PipelineReader<PSObject> output = 
                sender as PipelineReader<PSObject>;

            if (output != null)
            {
                while (output.Count > 0)
                {
                    SetText(output.Read().ToString());
                }
                return;
            }

            PipelineReader<object> error = 
                sender as PipelineReader<object>;

            if (error != null)
            {
                while (error.Count > 0)
                {
                    SetText(error.Read().ToString());
                }
                return;
            }
        }

        private void SetText(string text)
        {
            if (textBox2.InvokeRequired)
            {
                SetTextDelegate d = new SetTextDelegate(SetText);
                this.Invoke(d, new Object[] { text });
            }
            else
            {
                textBox2.Text += (text + Environment.NewLine);
            }
        }
    }
}

代码有效,但我在处理输出时遇到问题。 Pipeline.Output.Read()返回PSObject的一个实例,因此ToString()为不同的对象返回不同的东西。例如,如果我使用此PowerShell命令:

Get-ChildItem

输出是:

PSTestApp.exe
PSTestApp.pdb
PSTestApp.vshost.exe
PSTestApp.vshost.exe.manifest

如果我使用:

Get-Process

输出是:

...
System.Diagnostics.Process (csrss)
System.Diagnostics.Process (ctfmon)
System.Diagnostics.Process (devenv)
System.Diagnostics.Process (devenv)
...

我可以使用返回的PSObject实例来构造输出,但它会很好如果我可以使用现有的PowerShell格式并获得与控制台中相同的输出。当我运行应用程序并检查Runspace.RunspaceConfiguration.Formats时,计数为9,并且存在DotNetTypes.format.ps1xml,但我不知道如何应用该格式。

我注意到如果我在脚本末尾添加Out-String:

...
Pipeline pipeline = 
    runspace.CreatePipeline(textBox1.Text);
pipeline.Commands.Add("Out-String");
...

输出的格式与标准PowerShell控制台中的格式相同。这有效,但是如果我运行一个带有长输出的脚本需要一些时间来执行:

gci d:\ -recurse

Pipeline.Output.DataReady事件只引发一次(在执行结束Out-String之后),然后才将输出添加到文本框中。

有没有办法在托管的PowerShell实例中使用标准PowerShell输出格式?

1 个答案:

答案 0 :(得分:3)

如果你在out-string上使用-stream参数,我想你会发现它不会阻塞。

此外,如果您实际构建主机(实现主机接口,包括UI以及可能的rawui),您将实现处理“标准”主机输出的方法。

您也可以尝试使用out-default而不是out-string。我知道在自托管环境中我经常使用它。