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

如何为Invoke-Command子作业设置超时并显示运行进度?

远程子作业超时控制与进度监控实现方案

你当前的问题核心在于:试图在远程机器上执行Wait-Job -Timeout来控制本地Invoke-Command生成的子作业,这逻辑完全错误——远程机器的Job会话与本地的Invoke-Command作业是隔离的,远程机器根本看不到本地的子作业,所以那行超时代码完全无效。

核心解决思路

  • 本地追踪每个子作业的启动时间,在监控循环中检查运行时长,超过阈值直接终止该子作业
  • 保留原有进度展示逻辑,将超时判断整合到循环流程中

修改后的完整代码

$timeoutSeconds = 120 # 设置2分钟超时阈值
$JobFilePath = "你的审计脚本路径.ps1"
$Targets = @("目标机器1", "目标机器2") # 替换为实际目标服务器列表

Write-Host "Queueing job... " -NoNewline
# 启动远程审计作业
Invoke-Command -FilePath $JobFilePath -ComputerName $Targets -AsJob -ThrottleLimit 16 -JobName "AuditJob" -ErrorAction SilentlyContinue | Out-Null
# 获取所有子作业并记录启动时间
$childJobs = Get-Job -Name "AuditJob" -IncludeChildJob | Where-Object {$_.Name -ne "AuditJob"}
$jobStartTimes = @{}
foreach ($job in $childJobs) {
    $jobStartTimes[$job.Id] = $job.PSBeginTime
}
Write-Host "Done" -ForegroundColor Green

$origpos = $host.UI.RawUI.CursorPosition
[Console]::CursorVisible = $false

do{
    # 刷新子作业状态
    $childJobs = Get-Job -Name "AuditJob" -IncludeChildJob | Where-Object {$_.Name -ne "AuditJob"}
    
    # 检查并终止超时作业
    foreach ($job in $childJobs | Where-Object {$_.State -eq "Running"}) {
        $runDuration = (Get-Date) - $jobStartTimes[$job.Id]
        if ($runDuration.TotalSeconds -ge $timeoutSeconds) {
            Write-Host "`n终止超时作业: $($job.Name) (运行时长: $([math]::Round($runDuration.TotalSeconds))秒)" -ForegroundColor Red
            Stop-Job -Id $job.Id -ErrorAction SilentlyContinue
        }
    }

    # 统计各类状态的作业数量
    $Completed      = ($childJobs | Where-Object {$_.State -eq "Completed"}).Count
    $NotStarted     = ($childJobs | Where-Object {$_.State -eq "NotStarted"}).Count
    $Running        = ($childJobs | Where-Object {$_.State -eq "Running"}).Count
    $Stopped        = ($childJobs | Where-Object {$_.State -eq "Stopped"}).Count
    $Failed         = ($childJobs | Where-Object {$_.State -eq "Failed"}).Count
    $Blocked        = ($childJobs | Where-Object {$_.State -eq "Blocked"}).Count

    $Total = $childJobs.Count
    $JobsComplete = $Total - $NotStarted - $Running
    $PercentComplete = if ($Total -eq 0) {0} else {$JobsComplete/$Total}

    # 更新进度显示
    $host.UI.RawUI.CursorPosition = $origpos
    
    $statusStr = "[In Progress: $Running || Completed: $Completed || Not Started: $NotStarted || Failed/Timeout: $($Stopped + $Failed + $Blocked)]"
    Write-Host $statusStr
    $CurrentPos = $host.UI.RawUI.CursorPosition
    Write-Host (' ' * $CompleteStrLength)
    $host.UI.RawUI.CursorPosition = $CurrentPos
    
    $CompleteStr = "$([Math]::Ceiling($PercentComplete * 100))% complete"
    $CompleteStrLength = $CompleteStr.Length
    Write-Host $CompleteStr

    Start-Sleep -Milliseconds 250

}while ($JobsComplete -ne $Targets.Count)

# 清理残留作业
Get-Job -Name "AuditJob" -IncludeChildJob | Remove-Job -Force
[Console]::CursorVisible = $true

关键改进点

  1. 正确的超时控制:在本地记录每个子作业的启动时间,每次循环计算运行时长,超过阈值直接调用Stop-Job终止,这才是针对Invoke-Command子作业的有效控制方式
  2. 状态统计优化:直接用子作业集合的数量作为总计数,避免了原代码中累加可能出现的错误
  3. 超时状态提示:终止超时作业时输出明确的提示信息,便于排查问题
  4. 作业清理:循环结束后强制清理所有相关作业,避免残留的Job占用资源

内容的提问来源于stack exchange,提问作者Daniel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 03:07:14