c# - 如何在 Powershell 和 c# 之间传递标志变量?
问题描述
我有一个脚本,它使用一个包含 c# 代码的脚本块来启动一个 powershell 作业。
现在我有一个 sleep 命令可以让代码正确定位自己,但是更简洁的方法(如果可能的话)是让 psjob c# 代码设置一个标志并允许我的其余代码尽快启动它可以而不是等待 5 秒睡眠作为一个包罗万象。这可能吗?
$containerScript = {a mix of c# and powershell}
Start-Job -ScriptBlock $containerScript ;
sleep 5; # wait here for c# code to set up
Connect-MsolService;
因此,如果我在 c# psjob 脚本中设置了一个变量,bool started = true;
说明我如何使用循环而不是sleep 5
在上面显示的 powershell 代码中读取它,这在 psjob 运行空间和 c# 代码之外?
解决方案
您正在寻找的是一种自定义 .NET 类型的方法来异步写入 PowerShell 的输出流,以在方法本身返回之前向调用 PowerShell 代码发出条件信号。
Console.WriteLine()
不能这样做,因为它直接写入控制台,完全绕过 PowerShell 的输出流。
最好的方法是将您的 .NET 类型实现为 PowerShell cmdlet,这将允许您使用其.Write*()
方法立即写入 PowerShell 的输出流。
如果这不是一个选项,您可以使用 PowerShell SDK 写入调用运行空间的输出流,这有其局限性,如本答案中所述。
以下是适用于您的用例的技术演示:
# Start a background job.
$jb = Start-Job {
# Compile a sample type from C# source code.
Add-Type -TypeDefinition @'
using System.Management.Automation;
public class SomeClass
{
public static string DoStuff()
{
// ... perform initialization
// Instantly signal to the calling PowerShell session that initialization has
// completed, by calling Write-Information, which writes to the information stream (6).
using (PowerShell ps = PowerShell.Create(RunspaceMode.CurrentRunspace)) {
// IMPORTANT: Use .AddScript(), not .AddCommand().
// Even though .AddCommand() + .AddParameter() is arguably a cleaner way to
// formulate the command, it results in output that cannot be captured.
// Even though Write-Information is silent by default, the information *is* written to the stream.
ps.AddScript("Write-Information 'Initialized'").Invoke();
}
// Do other things.
System.Threading.Thread.Sleep(2000);
return "Done";
}
}
'@
# Call the sample type's method, which runs for a while, and partway
# through signals completion of the initialization portion with Write-Host output.
[SomeClass]::DoStuff()
}
# Wait for output from the job and output it as it arrives.
while ($jb.HasMoreData) {
# Receive pending stream output from the background job, capturing information-stream output separately.
Receive-Job $jb -InformationVariable iv
# Check if the initialization notification was received via the information stream.
# Note that $iv is always a *collection* type, even if there's only 1 message,
# and that the elements of that collection are of type [System.Management.Automation.InformationRecord]
if ($iv -and $iv[0].ToString() -eq 'Initialized') { 'Now initialized.'}
Start-Sleep -Milliseconds 100
}
Remove-Job $jb # clean up.
推荐阅读
- vba - 在 Word VBA 中查找字体大小之间的文本
- arrays - 使用带有 awk 的 bash 中的另一个有序数组模式对多行数组进行排序
- javascript - 无法在 window.onhashchange 处读取未定义的属性“parentNode”
- forms - 提交表单后,子表单值在接收端显示为 null
- html - 无法对齐 div 内容
- python - 如何立即退出一组循环并返回第一个循环?
- java - 我是否需要一个带有经常从站点消耗休息 api 的 java 应用程序的数据库?
- applescript - 使用 AppleScript 中的特定 x、y 坐标裁剪图像
- html - 当有水平滚动时,为什么不将块元素扩展到其子项的显式宽度
- windows - TLS 1.1 不会在 Windows Server 2008 R2 上禁用