How can you set a time limit for a PowerShell script to run for?
Something like this should work too...
$job = Start-Job -Name "Job1" -ScriptBlock {Do {"Something"} Until ($False)}Start-Sleep -s 10Stop-Job $job
Here's my solution, inspired by this blog post. It will finish running when all has been executed, or time runs out (whichever happens first).
I place the stuff I want to execute during a limited time in a function:
function WhatIWannaDo($param1, $param2){ # Do something... that maybe takes some time? Write-Output "Look at my nice params : $param1, $param2"}
I have another funtion that will keep tabs on a timer and if everything has finished executing:
function Limit-JobWithTime($Job, $TimeInSeconds, $RetryInterval=5){ try { $timer = [Diagnostics.Stopwatch]::StartNew() while (($timer.Elapsed.TotalSeconds -lt $TimeInSeconds) -and ('Running' -eq $job.JobStateInfo.State)) { $totalSecs = [math]::Round($timer.Elapsed.TotalSeconds,0) $tsString = $("{0:hh}:{0:mm}:{0:ss}" -f [timespan]::fromseconds($totalSecs)) Write-Progress "Still waiting for action $($Job.Name) to complete after [$tsString] ..." Start-Sleep -Seconds ([math]::Min($RetryInterval, [System.Int32]($TimeInSeconds-$totalSecs))) } $timer.Stop() $totalSecs = [math]::Round($timer.Elapsed.TotalSeconds,0) $tsString = $("{0:hh}:{0:mm}:{0:ss}" -f [timespan]::fromseconds($totalSecs)) if ($timer.Elapsed.TotalSeconds -gt $TimeInSeconds -and ('Running' -eq $job.JobStateInfo.State)) { Stop-Job $job Write-Verbose "Action $($Job.Name) did not complete before timeout period of $tsString." } else { if('Failed' -eq $job.JobStateInfo.State){ $err = $job.ChildJobs[0].Error $reason = $job.ChildJobs[0].JobStateInfo.Reason.Message Write-Error "Job $($Job.Name) failed after with the following Error and Reason: $err, $reason" } else{ Write-Verbose "Action $($Job.Name) completed before timeout period. job ran: $tsString." } } } catch { Write-Error $_.Exception.Message }}
... and then finally I start my function WhatIWannaDo
as a background job and pass it on to the Limit-JobWithTime
(including example of how to get output from the Job):
#... maybe some stuff before?$job = Start-Job -Name PrettyName -Scriptblock ${function:WhatIWannaDo} -argumentlist @("1st param", "2nd param")Limit-JobWithTime $job -TimeInSeconds 60Write-Verbose "Output from $($Job.Name): "$output = (Receive-Job -Keep -Job $job)$output | %{Write-Verbose "> $_"}#... maybe some stuff after?
I know this is an old post, but I have used this in my scripts.
I am not sure if its the correct use of it, but the System.Timers.Timer that George put up gave me an idea and it seems to be working for me.
I use it for servers that sometimes hang on a WMI query, the timeout stops it getting stuck.Instead of write-host I then output the message to a log file so I can see which servers are broken and fix them if needed.
I also don't use a guid I use the servers hostname.
I hope this makes sense and helps you.
$MyScript = { Get-WmiObject -ComputerName MyComputer -Class win32_operatingsystem }$JobGUID = [system.Guid]::NewGuid()$elapsedEventHandler = { param ([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e) ($sender -as [System.Timers.Timer]).Stop() Unregister-Event -SourceIdentifier $JobGUID Write-Host "Job $JobGUID removed by force as it exceeded timeout!" Get-Job -Name $JobGUID | Remove-Job -Force}$timer = New-Object System.Timers.Timer -ArgumentList 3000 #just change the timeout hereRegister-ObjectEvent -InputObject $timer -EventName Elapsed -Action $elapsedEventHandler -SourceIdentifier $JobGUID$timer.Start()Start-Job -ScriptBlock $MyScript -Name $JobGUID