将写入进度添加到 Get-Job/Wait-Job
Add Write-Progress to Get-Job/Wait-Job
我正在使用以下代码显示超时为 120 秒的 PowerShell 作业的结果。我想通过合并 Write-Progress
(基于完成的作业数)来增强此代码。我尝试使用 this example 作为参考,但是,当我尝试合并该代码时,进度条会短暂显示 在 所有作业都已完成后。
$Jobs = @()
$ForceStoppedIds = @{}
$Jobs += Get-Job
$Jobs | Wait-Job -Timeout 120 | Out-Null
$Jobs | ?{$_.State -eq 'Running'} | Stop-Job -PassThru | %{$ForceStoppedIds[$_.Id] = $true}
foreach ($Job in $Jobs) {
$Name = $Job.Name
$Output = (Get-Job -Name $Name | Receive-Job)
if ($ForceStoppedIds.Contains($Job.Id)) {
Write-Output "$($Name) - Device unable to process request within 2 minutes"
} else {
Write-Output $Output
}
}
Wait-Job -Timeout 120
将阻塞线程直到指定超时或所有作业完成,因此不可能同时显示进度和等待它们。我可以想到 2 个替代方案,第一个是创建一个 proxy function of Wait-Job
following the indications in ,另一个是定义你自己的函数,它的工作与 Wait-Job
类似,但不是阻塞线程,您可以添加一个循环,该循环将 运行 基于 2 个条件:
- 经过的时间小于或等于我们作为参数传递给函数的超时(为此我们可以使用
Diagnostics.Stopwatch
)。
- 并且,作业仍然是 运行(
$jobs
ArrayList
仍然存在)。
注意,下面的函数在大多数情况下应该有效,但是仅用于演示目的,不应依赖。 还值得一提的是,此函数只能用作管道函数,因为它依赖于 automatic variable $input
.
首先,我们定义了一个新函数,可用于显示进度以及基于超时等待我们的作业:
using namespace System.Collections.Generic
using namespace System.Diagnostics
using namespace System.Threading
function Wait-JobWithProgress {
[cmdletbinding()]
param(
[parameter(Mandatory, ValueFromPipeline)]
[object[]] $InputObject,
[parameter()]
[int] $TimeOut = [int]::MaxValue
)
begin {
$timer = [Stopwatch]::StartNew()
$jobs = [List[object]]::new()
}
process {
foreach($job in $InputObject) {
$jobs.Add($job)
}
}
end {
$total = $jobs.Count; $completed = 0
do {
$progress = @{
Activity = 'Waiting for Jobs'
Status = 'Remaining Jobs {0} of {1}' -f
($jobs.State -eq 'Running').Count, $total
PercentComplete = $completed / $total * 100
}
Write-Progress @progress
$id = [WaitHandle]::WaitAny($jobs.Finished, 200)
if($id -ne 258) {
# output this job
$jobs[$id]
# remove this job
$jobs.RemoveAt($id)
$completed++
}
} while($timer.Elapsed.Seconds -le $TimeOut -and $jobs)
# Stop the jobs not yet Completed and remove them
$jobs | Stop-Job -PassThru | ForEach-Object {
Write-Warning ("Job [#{0} - {1}] did not complete on time and was removed..." -f $_.Id, $_.Name)
Remove-Job $_
}
Write-Progress @progress -Completed
}
}
然后为了测试它,我们可以创建一些带有随机计时器的作业:
0..10 | ForEach-Object {
Start-Job {
Start-Sleep (Get-Random -Maximum 15)
[pscustomobject]@{
Job = $using:_
Result = "Hello from Job# $using:_"
}
}
} | Wait-JobWithProgress -TimeOut 10 |
Receive-Job -AutoRemoveJob -Wait | Format-Table -AutoSize
我正在使用以下代码显示超时为 120 秒的 PowerShell 作业的结果。我想通过合并 Write-Progress
(基于完成的作业数)来增强此代码。我尝试使用 this example 作为参考,但是,当我尝试合并该代码时,进度条会短暂显示 在 所有作业都已完成后。
$Jobs = @()
$ForceStoppedIds = @{}
$Jobs += Get-Job
$Jobs | Wait-Job -Timeout 120 | Out-Null
$Jobs | ?{$_.State -eq 'Running'} | Stop-Job -PassThru | %{$ForceStoppedIds[$_.Id] = $true}
foreach ($Job in $Jobs) {
$Name = $Job.Name
$Output = (Get-Job -Name $Name | Receive-Job)
if ($ForceStoppedIds.Contains($Job.Id)) {
Write-Output "$($Name) - Device unable to process request within 2 minutes"
} else {
Write-Output $Output
}
}
Wait-Job -Timeout 120
将阻塞线程直到指定超时或所有作业完成,因此不可能同时显示进度和等待它们。我可以想到 2 个替代方案,第一个是创建一个 proxy function of Wait-Job
following the indications in Wait-Job
类似,但不是阻塞线程,您可以添加一个循环,该循环将 运行 基于 2 个条件:
- 经过的时间小于或等于我们作为参数传递给函数的超时(为此我们可以使用
Diagnostics.Stopwatch
)。 - 并且,作业仍然是 运行(
$jobs
ArrayList
仍然存在)。
注意,下面的函数在大多数情况下应该有效,但是仅用于演示目的,不应依赖。 还值得一提的是,此函数只能用作管道函数,因为它依赖于 automatic variable $input
.
首先,我们定义了一个新函数,可用于显示进度以及基于超时等待我们的作业:
using namespace System.Collections.Generic
using namespace System.Diagnostics
using namespace System.Threading
function Wait-JobWithProgress {
[cmdletbinding()]
param(
[parameter(Mandatory, ValueFromPipeline)]
[object[]] $InputObject,
[parameter()]
[int] $TimeOut = [int]::MaxValue
)
begin {
$timer = [Stopwatch]::StartNew()
$jobs = [List[object]]::new()
}
process {
foreach($job in $InputObject) {
$jobs.Add($job)
}
}
end {
$total = $jobs.Count; $completed = 0
do {
$progress = @{
Activity = 'Waiting for Jobs'
Status = 'Remaining Jobs {0} of {1}' -f
($jobs.State -eq 'Running').Count, $total
PercentComplete = $completed / $total * 100
}
Write-Progress @progress
$id = [WaitHandle]::WaitAny($jobs.Finished, 200)
if($id -ne 258) {
# output this job
$jobs[$id]
# remove this job
$jobs.RemoveAt($id)
$completed++
}
} while($timer.Elapsed.Seconds -le $TimeOut -and $jobs)
# Stop the jobs not yet Completed and remove them
$jobs | Stop-Job -PassThru | ForEach-Object {
Write-Warning ("Job [#{0} - {1}] did not complete on time and was removed..." -f $_.Id, $_.Name)
Remove-Job $_
}
Write-Progress @progress -Completed
}
}
然后为了测试它,我们可以创建一些带有随机计时器的作业:
0..10 | ForEach-Object {
Start-Job {
Start-Sleep (Get-Random -Maximum 15)
[pscustomobject]@{
Job = $using:_
Result = "Hello from Job# $using:_"
}
}
} | Wait-JobWithProgress -TimeOut 10 |
Receive-Job -AutoRemoveJob -Wait | Format-Table -AutoSize