线程是否仍然使用 -asjob 和 wait-job 执行?
Do threads still execute using -asjob with wait-job?
大家好,下午好!
我有一个关于 -asjob
运行 invoke-command
的快速问题。
如果我 运行 2 Invoke-Command
使用 -asjob
,当我尝试接收输出时它是否同时 运行?这是否意味着 wait-job
等到指定的第一个作业完成 运行 得到下一个结果?
Write-Host "Searching for PST and OST files. Please be patient!" -BackgroundColor White -ForegroundColor DarkBlue
$pSTlocation = Invoke-Command -ComputerName localhost -ScriptBlock {Get-Childitem "C:\" -Recurse -Filter "*.pst" -ErrorAction SilentlyContinue | % {Write-Host $_.FullName,$_.lastwritetime}} -AsJob
$OSTlocation = Invoke-Command -ComputerName localhost -ScriptBlock {Get-Childitem "C:\Users\me\APpdata" -Recurse -Filter "*.ost" -ErrorAction SilentlyContinue | % {Write-Host $_.FullName,$_.lastwritetime} } -AsJob
$pSTlocation | Wait-Job | Receive-Job
$OSTlocation | Wait-Job | Receive-Job
另外,还有一个问题:我可以将作业的输出保存到一个变量中而不显示在控制台上吗?我试图让它检查是否有任何 return,如果有输出它,但如果没有做其他事情。
我试过了:
$job1 = $pSTlocation | Wait-Job | Receive-Job
if(!$job1){write-host "PST Found: $job1"} else{ "No PST Found"}
$job2 = $OSTlocation | Wait-Job | Receive-Job
if(!$job2){write-host "OST Found: $job2"} else{ "No OST Found"}
运气不好,输出如下:
注意:这个答案 不是 直接回答问题 - 请参阅 ;相反,它显示了一个 可重复使用的习惯用法,用于等待多个作业以 非阻塞 方式完成。
以下示例代码使用基于子进程的Start-Job
cmdlet to create local jobs, but the solution equally works with local thread-based jobs created by Start-ThreadJob
以及基于远程执行Invoke-Command -ComputerName ... -AsJob
问题中使用的命令。
它显示了一个可重复使用的习惯用法,用于等待多个作业以非阻塞方式完成,允许其他activity 在等待时,同时 在数组中收集每个作业的输出。
此处,仅在每个作业完成后 收集输出,但请注意,当它可用时,零碎地收集它也是一种选择,使用(可能多个)Receive-Job
甚至在作业完成之前调用。
# Start two jobs, which run in parallel, and store the objects
# representing them in array $jobs.
# Replace the Start-Job calls with your
# Invoke-Command -ComputerName ... -AsJob
# calls.
$jobs = (Start-Job { Get-Date; sleep 1 }),
(Start-Job { Get-Date '1970-01-01'; sleep 2 })
# Initialize a helper array to keep track of which jobs haven't finished yet.
$remainingJobs = $jobs
# Wait iteratively *without blocking* until any job finishes and receive and
# output its output, until all jobs have finished.
# Collect all results in $jobResults.
$jobResults =
while ($remainingJobs) {
# Check if at least 1 job has terminated.
if ($finishedJob = $remainingJobs | Where State -in Completed, Failed, Stopped, Disconnected | Select -First 1) {
# Output the just-finished job's results as part of custom object
# that also contains the original command and the
# specific termination state.
[pscustomobject] @{
Job = $finishedJob.Command
State = $finishedJob.State
Result = $finishedJob | Receive-Job
}
# Remove the just-finished job from the array of remaining ones...
$remainingJobs = @($remainingJobs) -ne $finishedJob
# ... and also as a job managed by PowerShell.
Remove-Job $finishedJob
} else {
# Do other things...
Write-Host . -NoNewline
Start-Sleep -Milliseconds 500
}
}
# Output the jobs' results
$jobResults
注:
- 很想尝试
$remainingJobs | Wait-Job -Any -Timeout 0
暂时 检查 以终止任何一项作业 而不会阻止执行 ,但是截至PowerShell 7.1 这不能按预期工作:即使已经完成的作业也永远不会返回 - 这似乎是 bug,已在 GitHub issue #14675. 中讨论
If I run 2 Invoke-Command's using -asjob, does it run simultaneously when I try to receive the output?
是的,PowerShell jobs always run in parallel, whether they're executing remotely, as in your case (with Invoke-Command -AsJob
, assuming that localhost
in the question is just a placeholder for the actual name of a different computer), or locally (using Start-Job
or Start-ThreadJob
)。
但是,通过使用(单独的)Wait-Job
调用,您同步 等待每个作业完成(也以固定顺序)。也就是说,每个 Wait-Job
调用都会阻止进一步执行,直到目标作业终止 。[1]
但是请注意,在您等待第一个作业完成时,两个 作业会继续执行。
如果您想在等待 两个 作业完成的同时执行其他操作,而不是以阻塞方式等待,则需要一种不同的方法,详见 .
can i save the output of the jobs to a variable without it showing to the console?
是的,但问题是在您的远程执行脚本块中 ({ ... }
) 您错误地使用了 Write-Host
试图输出 数据.
Write-Host
is typically the wrong tool to use, unless the intent is to write to the display only, bypassing the success output stream and with it the ability to send output to other commands, capture it in a variable, or redirect it to a file. To output a value, use it by itself; e.g., $value
instead of Write-Host $value
(or use Write-Output $value
, though that is rarely needed); see .
因此,您尝试将作业的输出收集到变量中 失败了 ,因为 Write-Host
输出 bypassed 成功了变量分配捕获并直接进入 host(控制台)的输出流:
# Because the job's script block uses Write-Host, its output goes to the *console*,
# and nothing is captured in $job1
$job1 = $pSTlocation | Wait-Job | Receive-Job
(顺便说一句,该命令可以简化为
$job1 = $pSTlocation | Receive-Job -Wait
).
[1] 请注意 Wait-Job
有一个可选的 -Timeout
参数,它允许您将等待限制在最多给定的秒数和 return如果目标作业尚未完成,则没有输出。但是,从 PowerShell 7.1 开始,-Timeout 0
用于非阻塞 轮询 作业是否完成 not 工作 - 参见 GitHub issue #14675.
大家好,下午好!
我有一个关于 -asjob
运行 invoke-command
的快速问题。
如果我 运行 2 Invoke-Command
使用 -asjob
,当我尝试接收输出时它是否同时 运行?这是否意味着 wait-job
等到指定的第一个作业完成 运行 得到下一个结果?
Write-Host "Searching for PST and OST files. Please be patient!" -BackgroundColor White -ForegroundColor DarkBlue
$pSTlocation = Invoke-Command -ComputerName localhost -ScriptBlock {Get-Childitem "C:\" -Recurse -Filter "*.pst" -ErrorAction SilentlyContinue | % {Write-Host $_.FullName,$_.lastwritetime}} -AsJob
$OSTlocation = Invoke-Command -ComputerName localhost -ScriptBlock {Get-Childitem "C:\Users\me\APpdata" -Recurse -Filter "*.ost" -ErrorAction SilentlyContinue | % {Write-Host $_.FullName,$_.lastwritetime} } -AsJob
$pSTlocation | Wait-Job | Receive-Job
$OSTlocation | Wait-Job | Receive-Job
另外,还有一个问题:我可以将作业的输出保存到一个变量中而不显示在控制台上吗?我试图让它检查是否有任何 return,如果有输出它,但如果没有做其他事情。
我试过了:
$job1 = $pSTlocation | Wait-Job | Receive-Job
if(!$job1){write-host "PST Found: $job1"} else{ "No PST Found"}
$job2 = $OSTlocation | Wait-Job | Receive-Job
if(!$job2){write-host "OST Found: $job2"} else{ "No OST Found"}
运气不好,输出如下:
注意:这个答案 不是 直接回答问题 - 请参阅
以下示例代码使用基于子进程的Start-Job
cmdlet to create local jobs, but the solution equally works with local thread-based jobs created by Start-ThreadJob
以及基于远程执行Invoke-Command -ComputerName ... -AsJob
问题中使用的命令。
它显示了一个可重复使用的习惯用法,用于等待多个作业以非阻塞方式完成,允许其他activity 在等待时,同时 在数组中收集每个作业的输出。
此处,仅在每个作业完成后 收集输出,但请注意,当它可用时,零碎地收集它也是一种选择,使用(可能多个)Receive-Job
甚至在作业完成之前调用。
# Start two jobs, which run in parallel, and store the objects
# representing them in array $jobs.
# Replace the Start-Job calls with your
# Invoke-Command -ComputerName ... -AsJob
# calls.
$jobs = (Start-Job { Get-Date; sleep 1 }),
(Start-Job { Get-Date '1970-01-01'; sleep 2 })
# Initialize a helper array to keep track of which jobs haven't finished yet.
$remainingJobs = $jobs
# Wait iteratively *without blocking* until any job finishes and receive and
# output its output, until all jobs have finished.
# Collect all results in $jobResults.
$jobResults =
while ($remainingJobs) {
# Check if at least 1 job has terminated.
if ($finishedJob = $remainingJobs | Where State -in Completed, Failed, Stopped, Disconnected | Select -First 1) {
# Output the just-finished job's results as part of custom object
# that also contains the original command and the
# specific termination state.
[pscustomobject] @{
Job = $finishedJob.Command
State = $finishedJob.State
Result = $finishedJob | Receive-Job
}
# Remove the just-finished job from the array of remaining ones...
$remainingJobs = @($remainingJobs) -ne $finishedJob
# ... and also as a job managed by PowerShell.
Remove-Job $finishedJob
} else {
# Do other things...
Write-Host . -NoNewline
Start-Sleep -Milliseconds 500
}
}
# Output the jobs' results
$jobResults
注:
- 很想尝试
$remainingJobs | Wait-Job -Any -Timeout 0
暂时 检查 以终止任何一项作业 而不会阻止执行 ,但是截至PowerShell 7.1 这不能按预期工作:即使已经完成的作业也永远不会返回 - 这似乎是 bug,已在 GitHub issue #14675. 中讨论
If I run 2 Invoke-Command's using -asjob, does it run simultaneously when I try to receive the output?
是的,PowerShell jobs always run in parallel, whether they're executing remotely, as in your case (with Invoke-Command -AsJob
, assuming that localhost
in the question is just a placeholder for the actual name of a different computer), or locally (using Start-Job
or Start-ThreadJob
)。
但是,通过使用(单独的)Wait-Job
调用,您同步 等待每个作业完成(也以固定顺序)。也就是说,每个 Wait-Job
调用都会阻止进一步执行,直到目标作业终止 。[1]
但是请注意,在您等待第一个作业完成时,两个 作业会继续执行。
如果您想在等待 两个 作业完成的同时执行其他操作,而不是以阻塞方式等待,则需要一种不同的方法,详见
can i save the output of the jobs to a variable without it showing to the console?
是的,但问题是在您的远程执行脚本块中 ({ ... }
) 您错误地使用了 Write-Host
试图输出 数据.
Write-Host
is typically the wrong tool to use, unless the intent is to write to the display only, bypassing the success output stream and with it the ability to send output to other commands, capture it in a variable, or redirect it to a file. To output a value, use it by itself; e.g., $value
instead of Write-Host $value
(or use Write-Output $value
, though that is rarely needed); see
因此,您尝试将作业的输出收集到变量中 失败了 ,因为 Write-Host
输出 bypassed 成功了变量分配捕获并直接进入 host(控制台)的输出流:
# Because the job's script block uses Write-Host, its output goes to the *console*,
# and nothing is captured in $job1
$job1 = $pSTlocation | Wait-Job | Receive-Job
(顺便说一句,该命令可以简化为
$job1 = $pSTlocation | Receive-Job -Wait
).
[1] 请注意 Wait-Job
有一个可选的 -Timeout
参数,它允许您将等待限制在最多给定的秒数和 return如果目标作业尚未完成,则没有输出。但是,从 PowerShell 7.1 开始,-Timeout 0
用于非阻塞 轮询 作业是否完成 not 工作 - 参见 GitHub issue #14675.