修改Wait-JobWithProgress函数,实现基于Timeout的剩余秒数进度条
问题
我正在使用Santiago Squarzon提供的Wait-JobWithProgress函数,希望修改该函数的进度条,使其基于指定的$Timeout值显示剩余秒数(SecondsRemaining)。
以下是函数中涉及Write-Progress的代码片段:
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)] [Job[]] $InputObject, [parameter()] [double] $TimeOut ) begin { $timer = [Stopwatch]::StartNew() $jobs = [List[Job]]::new() } process { foreach($job in $InputObject) { $jobs.Add($job) } } end { $total = $jobs.Count $completed = 0 $expression = { $true } if($PSBoundParameters.ContainsKey('TimeOut')) { $expression = { $timer.Elapsed.TotalSeconds -le $TimeOut } } while((& $expression) -and $jobs) { $status = "running job. Timeout in $($timeout / 60) minutes" $progress = @{ Activity = 'Waiting for Jobs' SecondsRemaining = #此处遇到问题 Status = $status } Write-Progress @progress
示例调用命令:
Start-Job {sleep -s 60} | Wait-JobWithProgress -Timeout 120
解决方案
要实现基于$Timeout的剩余秒数倒计时,通过总超时时间减去已流逝的秒数计算剩余时间即可,同时需确保数值不小于0(避免超时后出现负数)。另外原函数需要补充作业状态跟踪逻辑,才能完整实现进度反馈。修改后的完整循环及相关逻辑如下:
while((& $expression) -and $jobs) { # 检查并移除已完成的作业,更新完成计数 $completedJobs = $jobs | Where-Object { $_.State -in 'Completed', 'Failed', 'Stopped' } if ($completedJobs) { $completed += $completedJobs.Count foreach ($job in $completedJobs) { $jobs.Remove($job) } } # 计算剩余秒数:仅指定Timeout时才计算 $secondsRemaining = if ($PSBoundParameters.ContainsKey('TimeOut')) { [Math]::Max(0, $TimeOut - $timer.Elapsed.TotalSeconds) } else { $null # 未指定超时则不显示剩余时间 } # 更新状态文本,加入剩余时间信息 $status = if ($PSBoundParameters.ContainsKey('TimeOut')) { "Running jobs: $($jobs.Count)/$total. Remaining timeout: $([Math]::Round($secondsRemaining)) seconds" } else { "Running jobs: $($jobs.Count)/$total" } $progress = @{ Activity = 'Waiting for Jobs' Status = $status PercentComplete = if ($total -gt 0) { ($completed / $total) * 100 } else { 0 } SecondsRemaining = $secondsRemaining } Write-Progress @progress # 短暂休眠降低CPU占用 Start-Sleep -Milliseconds 500 } # 循环结束后关闭进度条 Write-Progress -Activity 'Waiting for Jobs' -Completed
关键逻辑说明:
- 剩余秒数计算:用
[Math]::Max(0, $TimeOut - $timer.Elapsed.TotalSeconds)确保剩余时间不会出现负数,即使超时后也显示0。 - 作业状态跟踪:每次循环检查已完成/失败/停止的作业,从列表中移除并更新完成计数,让进度条百分比能正确反映作业完成情况。
- 性能优化:添加
Start-Sleep -Milliseconds 500避免循环无休眠导致的高CPU使用率。 - 进度收尾:循环结束后调用
Write-Progress -Completed关闭进度条,避免残留。
内容的提问来源于stack exchange,提问作者Fitzgery
相关产品推荐
相关产品推荐

