How can you set a time limit for a PowerShell script to run for?

前端 未结 6 891
再見小時候
再見小時候 2021-01-05 15:36

I want to set a time limit on a PowerShell (v2) script so it forcibly exits after that time limit has expired.

I see in PHP they have commands like set_time_limit an

6条回答
  •  太阳男子
    2021-01-05 15:52

    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 60
    Write-Verbose "Output from $($Job.Name): "
    $output = (Receive-Job -Keep -Job $job)
    $output | %{Write-Verbose "> $_"}
    #... maybe some stuff after?
    

提交回复
热议问题