运行 C# 应用程序中的 PowerShell 进程并与之交互

Run a PowerShell process in a C# app and interact with it

我正在创建一个需要与 PowerShell 交互的 C#/WPF 应用程序(基本上,运行 命令和脚本)。创建进程并启动它不是问题,这很容易,但是当目标是在没有任何脚本的情况下启动它并在以后使其成为 运行 命令和脚本时变得更加困难:

  1. 启动 C# 应用程序
  2. 运行 PowerShell 并行处理
  3. [...] 做一些其他事情 [...]
  4. 运行 进程上的命令

我尝试了多种解决方案。 使用 System.Diagnostics.Process class,我可以启动进程,让它 运行,但即使我重定向流,写入标准输入也不起作用:

var startInfo = new ProcessStartInfo()
{
    FileName = "powershell.exe",
    Arguments = "-ExecutionPolicy Bypass -NoLogo -NoExit",
    CreateNoWindow = true,
    RedirectStandardError = true,
    RedirectStandardInput = true,
    RedirectStandardOutput = true,
    UseShellExecute = false,
    WindowStyle = ProcessWindowStyle.Hidden
};
_ps = new Process()
{
    EnableRaisingEvents = true,
    StartInfo = startInfo
};
_ps.Start();

[...]

_ps.StandardInput.WriteLine(TextBox_Input.Text); // No effect

使用 System.Management.Automation.PowerShell class 不是更好,我可以准备管道(添加要执行的脚本),调用它,但是,我不能 运行 稍后保留脚本进程还活着。

我需要尽快启动进程以便能够向它发送命令并运行它们越快越好(并避免进程启动会导致延迟)。

如评论中所述,在应用程序启动时设置(并打开)运行空间:

Runspace rs;
public MainWindow()
{
    InitializeComponent();
    rs = RunspaceFactory.CreateRunspace();
    rs.Open();
}

现在,您只需要一个创建 PowerShell 实例并在运行空间中执行它的函数:

private Collection<PSObject> RunScript(string script)
{
    using(PowerShell ps = PowerShell.Create())
    {
        ps.AddScript(script);
        ps.Runspace = rs;
        return ps.Invoke();
    }
}

然后,在 运行 的事件处理程序中,用户输入的脚本:

private void button_Click(object sender, RoutedEventArgs e)
{
    Collection<PSObject> returnedObjects = RunScript(TextBox_Input.Text);
    // do what you want with returnedObjects if necessary
}

这当然是一个过于简化的示例。在实际应用程序中,您将检查 error and warning streams、使用 APM (BeginInvoke()/EndInvoke()) 等