Я нашел пример C # здесь асинхронного вызова скрипта PowerShell из хост-приложения (в папке Глава 6 - Чтение с событиями) и пытаюсь использовать его в приложении Windows Forms.
У меня есть кнопка (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?