在托管PowerShell运行空间的.NET应用程序中,是否可以将主机应用程序功能导出到该运行空间,以便我拥有对我的UI产生影响的PowerShell cmdlet?
我的目标只是能够从长时间运行的PowerShell脚本向我的主机应用程序UI报告进度消息(因为托管PowerShell我没有控制台窗口。)我想象的是:
C#:
// Speculative pseudocode:
class ReportProgressCmdlet : Cmdlet { ... } // Reports a message on the UI.
...
myRunspace.Register(new ReportProgressCmdlet(myUI));
的PowerShell:
Report-Progress "Starting step 1." # UI shows "Starting step 1."
...
Report-Progress "Step 1 failed."
这可能吗?如果我错了,很高兴听到不同的解决方案(活动?)我已经阅读了以下所有问题以及许多其他类似的问题,我并不认为他们是我正在寻找的:< / p>
How to expose functionality to PowerShell from within your application
Powershell Call Assembly Delegate
How to programmatically add a PSCmdlet to a Powershell pipeline?
答案 0 :(得分:0)
UPDATE :我在下面介绍的技术适用于任意GUI操作,但出于我的目的(以清理后的格式显示PowerShell输出),实现自定义更容易PSHost,PSHostUserInterface和PSHostRawUserInterface使脚本端更简单(您使用熟悉的写输出,写主机,写错误等,而不是一些定制的输出API。这也使脚本保持灵活性,以防您想要在你的主机之外运行它)。请参阅https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx以获取一个好例子。
Cmdlets被证明是错误的方法 - 要做的是通过“SessionState”API将GUI对象实例暴露给PowerShell,然后PowerShell代码可以直接使用它们。这是你如何做到的:
带来正确的命名空间:
using System.Management.Automation;
using System.Management.Automation.Runspaces;
然后创建一个Runspace并将您的GUI对象实例注入PowerShell变量。 (这里我传递的是一个暴露一个Messages集合的viewmodel,但你可能希望在现实世界中更好地分层。)你可以在创建运行空间时使用InitialSessionState,如:
var iss = InitialSessionState.CreateDefault();
iss.Variables.Add(new SessionStateVariableEntry("thing", this.DataContext, "it's the data context"));
using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
{
runspace.ThreadOptions = PSThreadOptions.UseCurrentThread;
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = runspace;
ps.AddScript(@"$thing.Messages.Add('in which PowerShell can make stuff happen on the GUI via InitialSessionState')");
ps.Invoke();
}
runspace.Close();
}
或者,您可以在使用Runspace.SessionStateProxy.SetVariable(name,object)创建和打开Runspace后注入对象实例。除了你不必注入InitialSessionState之外,那个代码的代码是相同的。
Doug Finke得到了这个奖励,因为我从他发现的截屏视频中学到了这个技术:
http://www.dougfinke.com/blog/index.php/2009/09/02/how-to-host-powershell-in-a-wpf-application/
答案 1 :(得分:0)
我在WPF + XAML中创建了一个进度条,并在不同的Runspace中运行它。这段代码可能正是您所需要的。
https://gallery.technet.microsoft.com/Script-New-ProgressBar-329abbfd
这是一个关于如何使用我运行循环的函数,更新新的Runspace的示例。并检测窗口/进度条是否已关闭,并停止执行代码。
# Create the window form in a different namespace
Load-Window
For ($i = 0; $i -lt 100; $i++) {
#Update the progressbar
$Result = Update-ProgressBar -Percent $i -Label1Text "$i / 100"
# If you want to simply check if the window is still active
# Update-Window will return if the form/window is active
# $Result = Update-Window
#If the window is close, stop the loop
If ($Result -eq $False) { Break }
Sleep -Milliseconds 100
}
Close-Window