You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 18:01:07