快速故事: 为了试验PowerShell,我试图学习如何有效地多线程化脚本。
现在我知道如何启动作业并将变量传递给我的第二个脚本,但是我已经决定尝试找出如何解决这个问题:
start-job ((Split-Path -parent $PSCommandPath) + "\someScript.ps1") -ArgumentList (,$argList)
进入这个:
start-job (. ((Split-Path -parent $PSCommandPath) + "\someScript.ps1")) -ArgumentList (,$argList)
原因是我在父脚本中声明了一个变量,如下所示:
New-Variable var -value 0 -Option AllScope
并在子脚本中:var = "something"
第一个start-job传递了我的参数,但是孩子没有设置全局'var'变量
第二个没有传递我的参数,但是子脚本设置了父节点中定义的全局变量就好了。 $ argList变量将填充到第二个启动作业中的这行代码,但是在执行该行之后,调试显示$ argList变量为null并且我得到“Start-Job:无法将参数绑定到参数” ScriptBlock'因为它是null。“
为了论证,假设直到所陈述的代码行,变量包含它们应该的数据。
有人可以帮助我解决两次尝试的错误。 谷歌没有给我任何具体的问题答案。 提前感谢我能得到的任何帮助。
编辑:
使用Start-Job (. ((Split-Path -parent $PSCommandPath) + "\someScript.ps1") $argList)
完成我的目标然而我不断得到Start-Job : Cannot bind argument to parameter 'ScriptBlock' because it is null.
即使参数在脚本块中,并且子脚本正在获取并处理参数。
答案 0 :(得分:0)
当您调用Start-Job
时,脚本将在完全独立的范围(PowerShell Runspace)中运行。您无法通过Start-Job
直接调用直接调用的脚本。您必须让外部脚本处理通过-ArgumentList
传入的参数,然后通过Receive-Job
将其返回到原始主机Runspace。
这是一个完整的例子:
$a = 1;
$Job = Start-Job -FilePath C:\test\script.ps1 -ArgumentList $a;
Write-Host -Object "Before: $a"; # Before
Wait-Job -Job $Job;
$a = Receive-Job -Job $Job -Keep;
Write-Host -Object "After: $a"; # After
以下是文件c:\test\script.ps1
的内容:
Write-Output -InputObject (([int]$args[0]) += 5);
如果您想证明我之前关于Start-Job
创建新线程和PowerShell Runspace以及新Thread
的观点,请运行此脚本:
# 1. Declare a thread block that retrieves the Runspace ID & ThreadID
$ThreadBlock = {
[runspace]::DefaultRunspace.InstanceId.ToString();
[System.Threading.Thread]::CurrentThread.ManagedThreadId;
};
# 2. Start a job and wait for it to finish
$Job = Start-Job -ScriptBlock $ThreadBlock;
[void](Wait-Job -Job $Job);
Receive-Job -Job $Job -Keep;
# 3. Call the same ScriptBlock locally
& $ThreadBlock;
# 4. Note the differences in the Runspace InstanceIDs and ThreadIDs
您可以在PowerShell作业完成之前多次调用Receive-Job
来检索结果。以下是理论上如何运作的一个例子:
$ScriptBlock = {
1..5 | % { Start-Sleep -Seconds 2; Write-Output -InputObject $_; };
};
$Job = Start-Job -ScriptBlock $ScriptBlock;
while ($Job.JobStateInfo.State -notin ([System.Management.Automation.JobState]::Completed,[System.Management.Automation.JobState]::Failed)) {
Start-Sleep -Seconds 3;
$Results = Receive-Job -Job $Job;
Write-Host -Object ('Received {0} items: {1}' -f $Results.Count, ($Results -join ' '));
}