MKA*_*NET 2 powershell start-job powershell-jobs progress-bar
我使用下面的代码来显示 PowerShell 作业的结果,超时时间为 120 秒。我想通过合并Write-Progress(基于完成的作业数量)来增强此代码。我尝试使用此示例作为参考,但是,当我尝试合并该代码时,进度条会在所有作业全部完成后短暂显示。
$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
}
}
Run Code Online (Sandbox Code Playgroud)
Wait-Job -Timeout 120将阻塞线程,直到指定的超时或所有作业完成,因此不可能同时显示进度并等待它们。
我能想到有两种选择,第一个是创建代理命令/代理函数以扩展其功能。
这些博客演示了如何做到这一点:
您还可以按照此有用答案中的指示进行操作。
另一种选择是定义您自己的函数,该函数执行类似的工作Wait-Job,但是您可以添加一个基于两个条件运行的循环,而不是阻塞线程:
Diagnostics.Stopwatch为此使用)。$jobs List<T>仍填充)。请注意,下面的函数在大多数情况下应该可以工作,但仅用于演示目的,不应依赖。
首先,我们定义一个新函数,可用于显示进度并根据超时等待作业:
using namespace System.Collections.Generic
using namespace System.Diagnostics
using namespace System.Threading
using namespace System.Management.Automation
function Wait-JobWithProgress {
[cmdletbinding()]
param(
[parameter(Mandatory, ValueFromPipeline)]
[object[]] $InputObject,
[parameter()]
[ValidateRange(1, [double]::MaxValue)]
[double] $TimeOut # In seconds!
)
begin {
$jobs = [List[object]]::new()
if ($withTimeOut = $PSBoundParameters.ContainsKey('TimeOut')) {
$span = [timespan]::FromSeconds($TimeOut)
}
}
process {
$jobs.AddRange($InputObject)
}
end {
$timer = [Stopwatch]::StartNew()
$total = $jobs.Count
$completed = 0.1
while ($jobs.Count) {
if ($withTimeOut -and $timer.Elapsed -gt $span) {
break
}
$remaining = $total - $completed
$average = $timer.Elapsed.TotalSeconds / $completed
$estimate = [math]::Round($remaining * $average)
$status = 'Completed Jobs: {0:0} of {1}' -f $completed, $total
$progress = @{
Activity = 'Waiting for Jobs'
PercentComplete = $completed / $total * 100
Status = $status
SecondsRemaining = $estimate
}
Write-Progress @progress
$id = [WaitHandle]::WaitAny($jobs.Finished, 200)
if ($id -eq [WaitHandle]::WaitTimeout) {
continue
}
# output this job
$jobs[$id]
# remove this job
$jobs.RemoveAt($id)
$completed++
}
# Stop the jobs not yet Completed and remove them
$jobs | Stop-Job -PassThru | ForEach-Object {
Remove-Job -Job $_
'Job [#{0} - {1}] did not complete on time and was removed.' -f $_.Id, $_.Name
} | Write-Warning
Write-Progress @progress -Completed
}
}
Run Code Online (Sandbox Code Playgroud)
然后为了测试它,我们可以使用随机计时器创建一些作业:
0..10 | ForEach-Object {
Start-Job {
Start-Sleep (Get-Random -Minimum 5 -Maximum 15)
[pscustomobject]@{
Job = $using:_
Result = 'Hello from [Job #{0:D2}]' -f $using:_
}
}
} | Wait-JobWithProgress -TimeOut 10 |
Receive-Job -AutoRemoveJob -Wait | Format-Table -AutoSize
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1294 次 |
| 最近记录: |