托管PowerShell:PowerShell vs. Runspace vs. RunspacePool vs. Pipeline

19

我正在尝试在我的应用程序中添加一些相对有限的PowerShell支持:我想要定期运行用户定义的PowerShell脚本并显示任何输出,最终能够处理进度通知和用户提示请求。我不需要命令行交互式支持,也不需要(我认为)远程访问或同时运行多个脚本的能力,除非用户脚本自身从我托管的shell内部执行。我最终想以异步或后台线程运行脚本,并可能使用一些初始变量和可能一个cmdlet来初始化shell,但这就是此功能可能变得“花哨”的程度。

我一直在阅读关于编写主机应用程序代码的MSDN文档,但虽然它愉快地解释了如何创建PowerShell对象、Runspace、RunspacePool或Pipeline,却没有说明为什么要选择其中任何一种方法。

认为我现在只剩下其中两种方法可选,但我想听听关于采取哪种方法更好的反馈:

PowerShell shell = PowerShell.Create();
shell.AddCommand(/* set initial state here? */);
shell.AddStatement();
shell.AddScript(myScript);
shell.Invoke(/* can set host! */);

或者:

Runspace runspace = RunspaceFactory.CreateRunspace(/* can set host and initial state! */);
PowerShell shell = PowerShell.Create();
shell.Runspace = runspace;
shell.AddScript(myScript);
shell.Invoke(/* can set host here, too! */);

其中一个必需的 PSHost 派生类方法是 EnterNestedPrompt(),我不知道运行的用户定义脚本是否会调用它。如果可以的话,那么我将负责 "启动一个新的嵌套输入循环"(详见此处)... 如果这会影响以上所述的路径,那也是好事。

谢谢!


2
你实际上不需要一个主机。只需确保避免调用Write-Host,Read-Host等函数即可。有一种方法可以检查PS是否连接了主机,但我暂时不记得了。 - Simon Ejsing
在我的情况下,我可能不一定需要一个PSHost,但我想要一个...我预计用户定义的脚本会有偶尔的诊断消息,我希望能够显示它们。(我会编辑原始帖子以使其更清晰明了。) - JaredReisinger
2个回答

6

它们是什么?

  • 管道(Pipeline)

管道是在 PowerShell 脚本中连接命令的一种方式。例如:你可以通过使用 |Get-ChildItem 命令的输出传递给 Where-Object 命令以对其进行过滤:

Get-ChildItem | Where-Object {$_}
  • PowerShell对象

PowerShell对象指的是PowerShell会话,就像您启动powershell.exe时得到的那个会话。

  • Runspace

每个PowerShell会话都有自己的运行空间(您始终会从Get-Runspace获得输出)。它定义了PowerShell会话的状态。因此,一个运行空间的InitialSessionState对象/属性。您可以决定创建一个新的PowerShell会话,具有其自己的运行空间,从而实现一种多线程。

  • RunspacePool

最后是RunspacePool。顾名思义,它是一组运行空间(或PowerShell会话),可用于处理许多复杂任务。只要池中的一个运行空间完成了其任务,它就可以接下来的任务,直到所有任务都完成。(10个运行空间有100个任务要做:平均每个处理10个,但一个可能处理8个,而其他两个处理11个...)


什么时候使用什么?

  • 管道

管道用于脚本。它使构建复杂脚本更容易,并应尽可能经常使用。

  • PowerShell对象

每当您需要一个新的PowerShell会话时,都可以使用PowerShell对象。您可以在现有脚本(无论是C#还是PowerShell)中创建一个会话。它对于轻松的多线程非常有用。单独使用它将创建默认会话。

  • Runspace

如果要创建非标准的PowerShell会话,则可以在创建带有它的PowerShell会话之前操作运行空间对象。当您想要在额外的运行空间中共享同步变量、函数或类时,它非常有用。稍微复杂一些的多线程。

  • RunspacePool

如前所述,这是处理重型工作的重型工具。当脚本的执行需要数小时,并且您需要经常执行时。例如。与远程控制结合使用,您可以同时在大型集群的每个节点上安装某些内容等。


0

你想太多了。你展示的代码样本是一个很好的开始。现在你只需要读取Invoke()的结果并检查错误和警告流。

PowerShell主机提供了一些钩子,RunSpace可以使用这些钩子与用户进行通信,如流和格式输出、显示进度、报告错误等。对于你想要做的事情,你不需要PowerShell Host。你可以使用PowerShell类从脚本执行中读取结果,检查错误、警告、读取输出流,并使用你的应用程序的设施向用户显示通知。这将比编写整个PowerShell主机来显示消息框如果检测到错误更加直接和有效。

此外,当创建PowerShell对象时,它已经有了一个Runspace,你不需要再给它一个。如果你需要保留Runspace以保留环境,只需保留整个PowerShell对象,并在每次调用Invoke后清除Commands和所有Streams即可。

你接下来应该问的问题是如何处理PowerShell::Invoke()的结果并读取PowerShell::Streams


嘿!你能详细说明一下如何“在调用Invoke后每次保留整个PowerShell对象并清除命令和所有流”吗?我目前没有使用runspaces,并且想出于这个原因实现它们,但看起来我可以仅使用PowerShell方法实现这一点?谢谢!! - Andrew Morpeth
请提出一个恰当的问题。在评论中回答问题是没有得分的。;) - Serjx86

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接