我找到了一个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输出格式?
答案 0 :(得分:3)
如果你在out-string上使用-stream参数,我想你会发现它不会阻塞。
此外,如果您实际构建主机(实现主机接口,包括UI以及可能的rawui),您将实现处理“标准”主机输出的方法。
您也可以尝试使用out-default而不是out-string。我知道在自托管环境中我经常使用它。