Powershell 管理后台作业的运行时间。如果x秒后未完成超时,

Powershell 管理后台作业的运行时间。如果x秒后未完成超时,,powershell,timeout,start-job,Powershell,Timeout,Start Job,我想给我的后台作业计时(从start job开始),并在x秒后超时。然而,我发现很难跟踪每个单独作业的运行时间(我正在运行大约400个作业) 我希望有一种方法可以使作业超时,并将其设置为失败(如果在X秒内未完成),但我没有找到超时参数 跟踪作业的单个运行时间的好方法是什么 我想我可以创建一个包含每个作业的开始时间和作业id的哈希表,对照运行状态检查并手动超时,但这听起来有点像“发明轮子”。 有什么想法吗 编辑 感谢大家就这个话题进行了富有成效的讨论,并给予了巨大的启发 您可以指定等待作业的超时选

我想给我的后台作业计时(从
start job
开始),并在
x
秒后超时。然而,我发现很难跟踪每个单独作业的运行时间(我正在运行大约400个作业)

我希望有一种方法可以使作业超时,并将其设置为
失败
(如果在X秒内未
完成
),但我没有找到超时参数

跟踪作业的单个运行时间的好方法是什么

我想我可以创建一个包含每个作业的开始时间和作业id的哈希表,对照
运行状态检查并手动超时,但这听起来有点像“发明轮子”。
有什么想法吗

编辑
感谢大家就这个话题进行了富有成效的讨论,并给予了巨大的启发

您可以指定等待作业的超时选项:

-超时

确定每个后台作业的最大等待时间(秒)。 默认值,-1将等待作业完成,无论作业完成多长时间 跑。当您提交Wait Job命令而不是 启动作业命令

如果超过此时间,则等待结束,并显示命令提示 返回,即使作业仍在运行。未显示任何错误消息 显示

下面是一些示例代码:

这部分只是做了一些测试工作:

Remove-Job -Name *
$jobs = @()
1..10 | % {
    $jobs += Start-Job -ScriptBlock {
        Start-Sleep -Seconds (Get-Random -Minimum 5 -Maximum 20)
    }
}
变量
$timedOutJobs
包含超时的作业。然后,您可以重新启动它们或您所拥有的一切

$jobs | Wait-Job -Timeout 10 
$timedOutJobs = Get-Job | ? {$_.State -eq 'Running'} | Stop-Job -PassThru

只需浏览正在运行的作业列表,并停止任何超过超时规格的作业,例如:

$timeout = [timespan]::FromMinutes(1) $now = Get-Date Get-Job | Where {$_.State -eq 'Running' -and (($now - $_.PSBeginTime) -gt $timeout)} | Stop-Job $timeout=[timespan]::FromMinutes(1) $now=获取日期 获取作业|其中{$\.State-eq'Running'-和 ($now-$\PSBeginTime)-gt$timeout)}停止作业 顺便说一句,作业对象的属性比默认格式显示的更多,例如:

3 > $job | fl * State : Running HasMoreData : True StatusMessage : Location : localhost Command : Start-sleep -sec 30 JobStateInfo : Running Finished : System.Threading.ManualResetEvent InstanceId : de370ea8-763b-4f3b-ba0e-d45f402c8bc4 Id : 3 Name : Job3 ChildJobs : {Job4} PSBeginTime : 3/18/2012 11:07:20 AM PSEndTime : PSJobType : BackgroundJob Output : {} Error : {} Progress : {} Verbose : {} Debug : {} Warning : {} 3>$job | fl* 状态:正在运行 哈斯莫尔数据:对 状态信息: 位置:本地主机 命令:开始睡眠-第30秒 JobStateInfo:正在运行 完成:System.Threading.ManualResetEvent 实例ID:de370ea8-763b-4f3b-ba0e-d45f402c8bc4 身份证号码:3 姓名:Job3 子作业:{Job4} PSBeginTime:3/18/2012 11:07:20上午 PSEndTime: PSJobType:背景作业 输出:{} 错误:{} 进展:{} 详细:{} 调试:{} 警告:{}
您可以使用计时器的哈希表:

 $jobtimer = @{}

 foreach ($job in $jobs){
   start-job -name $job -ScriptBlock {scriptblock commands}
   $jobtimer[$job] = [System.Diagnostics.Stopwatch]::startnew()
   }

每个作业的运行时间将以$jobtimer[$job]为单位。已用时间

为完整性起见,此答案结合了每个作业的最大秒数和运行的最大并发作业数。因为这是大多数人追求的

下面的示例检索每个打印服务器的打印机配置。可以有3000多台打印机,所以我们增加了节流功能

$i = 0
$maxConcurrentJobs = 40
$maxSecondsPerJob = 60
$jobTimer = @{ }

$StopLongRunningJobs = {
    $jobTimer.GetEnumerator().where( {
            ($_.Value.IsRunning) -and
            ($_.Value.Elapsed.TotalSeconds -ge $maxSecondsPerJob)
        }).Foreach( {
            $_.Value.Stop()
            Write-Verbose "Stop job '$($_.Name.Name)' that ran for '$($_.Value.Elapsed.TotalSeconds)' seconds"
            Stop-Job $_.Name
        })
}

Foreach ($Computer in @($GetPrinterJobResults.Where( { $_.Data }) )) {
    foreach ($Printer in $Computer.Data) {
        do {
            & $StopLongRunningJobs
            $running = @(Get-Job -State Running)
            $Wait = $running.Count -ge $maxConcurrentJobs

            if ($Wait) {
                Write-Verbose 'Waiting for jobs to fininsh'
                $null = $running | Wait-Job -Any -Timeout 5
            }
        } while ($Wait)

        $i++
        Write-Verbose "$I $($Computer.ComputerName) Get print config '$($Printer.Name)'"
        $Job = $Printer | Get-PrintConfiguration -AsJob -EA Ignore
        $jobtimer[$Job] = [System.Diagnostics.Stopwatch]::StartNew()
    }
}

$JobResult = Get-Job | Wait-Job -Timeout $maxSecondsPerJob -EA Ignore
$JobResult = Get-Job | Receive-Job -EA Ignore
$JobResult.count

我可能会想出类似您在上一段中提到的哈希表解决方案。似乎是个好主意。Psbegintime正是我要找的!但是我找不到它。您正在运行V2还是V3?目前正在运行V3。如果V2没有该字段,那么是的,只需创建一个哈希表,将$job对象(或id)映射到创建作业时创建的时间戳。我在Win8 beta(PSv3)上,而且我似乎也没有Ps*属性:/
(Start job-ScriptBlock{gp}gm-MemberType属性Ps*)。Count
0
.Hmm,我想我只能说,希望这个属性能进入最终版本。:-)Windows 7上的Powershell Beta 3中也没有PSBegintime。祈祷这会进入国际泳联:)这也是我的第一个想法,但等待工作的一个问题是它被阻塞了。如果脚本可以在OP的400个作业完成或超时时被完全阻止,那么这将起作用。在使用等待作业超时时,还有一个隐含的假设,即所有作业或多或少都在同一时间开始。@KeithHill Sune在SO的帮助下开发了这个脚本。lol。前面的一个问题涉及如何限制作业。我不认为400将同时运行。你是对的@AndyArismendi!我正在扼杀工作。。当时只跑了20英里(我发现这是一个不错的甜蜜点)。如果我在脚本末尾(或脚本中的任何位置)执行等待作业,脚本将重新提交所有超时的作业。。我需要把这个限制在油门水平。我想我必须对foreach循环中的哈希表进行测试。无论如何,谢谢:):)@Sune如果您将
$timedOutJobs
制作为一个数组,并将其添加到您运行的每组作业中,您可以使用此方法来完成此任务。假设您运行20并收集阵列中该块的超时作业,然后再运行20并收集阵列中该块的超时作业。最后,您将拥有一个包含所有超时作业的数组。这将给所有作业同等的超时时间。或者,只需重新提交第一个作业。因此,如果你保持20次运行,并且有一个按时间顺序排列的作业列表。然后,当等待超时时,您可以停止并重新提交一个作业(列表中第一个作业,即运行时间最长的作业)。这非常完美。但是,我在直接引用值而不将其设置为变量时遇到问题。。为什么
get job | foreach{echo$jobtimer[$\.name].appeased.totalseconds}
不起作用,但
$jobtimer[4]。appeased.totalseconds
起作用?