我想在PowerShell(v2)脚本上设置一个时间限制,以便在该时间限制到期后强行退出。
我在PHP中看到他们有像set_time_limit和max_execution_time这样的命令,你可以限制脚本甚至函数可以执行多长时间。
使用我的脚本,查看时间的do / while循环是不合适的,因为我正在调用一个可以挂起很长时间的外部代码库。
我想限制一段代码并且只允许它运行x秒,之后我将终止该代码块并向用户返回脚本超时的响应。
我查看了后台作业,但是它们在不同的线程中运行,因此不会对父线程具有终止权限。
是否有人处理此问题或有解决方案?
谢谢!
答案 0 :(得分:3)
这样的事也应该有用......
$job = Start-Job -Name "Job1" -ScriptBlock {Do {"Something"} Until ($False)}
Start-Sleep -s 10
Stop-Job $job
答案 1 :(得分:1)
以下是使用Timer的示例。我没有亲自试过,但我认为它应该有效:
function Main
{
# do main logic here
}
function Stop-Script
{
Write-Host "Called Stop-Script."
[System.Management.Automation.Runspaces.Runspace]::DefaultRunspace.CloseAsync()
}
$elapsedEventHandler = {
param ([System.Object]$sender, [System.Timers.ElapsedEventArgs]$e)
Write-Host "Event handler invoked."
($sender -as [System.Timers.Timer]).Stop()
Unregister-Event -SourceIdentifier Timer.Elapsed
Stop-Script
}
$timer = New-Object System.Timers.Timer -ArgumentList 2000 # setup the timer to fire the elapsed event after 2 seconds
Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier Timer.Elapsed -Action $elapsedEventHandler
$timer.Start()
Main
答案 2 :(得分:1)
我知道这是一篇旧帖子,但我在我的剧本中使用了这个帖子。
我不确定它是否正确使用它,但George提出的System.Timers.Timer给了我一个想法,它似乎对我有用。
我将它用于有时挂在WMI查询上的服务器,超时会阻止它卡住。 而不是写主机我然后将消息输出到日志文件,以便我可以看到哪些服务器坏了并在需要时修复它们。
我也不使用guid我使用服务器主机名。
我希望这有意义并帮助你。
$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 here
Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action $elapsedEventHandler -SourceIdentifier $JobGUID
$timer.Start()
Start-Job -ScriptBlock $MyScript -Name $JobGUID
答案 3 :(得分:0)
怎么样呢?
## SET YOUR TIME LIMIT
## IN THIS EXAMPLE 1 MINUTE, BUT YOU CAN ALSO USE HOURS/DAYS
# $TimeSpan = New-TimeSpan -Days 1 -Hours 2 -Minutes 30
$TimeSpan = New-TimeSpan -Minutes 1
$EndTime = (Get-Date).AddMinutes($TimeSpan.TotalMinutes).ToString("HH:mm")
## START TIMED LOOP
cls
do
{
## START YOUR SCRIPT
Write-Warning "Test-Job 1...2...3..."
Start-Sleep 3
Write-Warning "End Time = $EndTime`n"
}
until ($EndTime -eq (Get-Date -Format HH:mm))
## TIME REACHED AND END SCRIPT
Write-Host "End Time reached!" -ForegroundColor Green
使用小时或天作为计时器时,请确保调整$ TimeSpan.TotalMinutes 和HH:mm格式,因为这在示例中不方便使用天。
答案 4 :(得分:0)
这是我受this blog post启发的解决方案。完成所有操作或时间用完(以先发生的为准)时,它将结束运行。
我将要在有限时间内执行的内容放在一个函数中:
function WhatIWannaDo($param1, $param2)
{
# Do something... that maybe takes some time?
Write-Output "Look at my nice params : $param1, $param2"
}
我还有另一个功能,可以在计时器上查看选项卡,以及是否一切执行完毕:
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
}
}
...,最后我将函数WhatIWannaDo
作为后台作业启动,并将其传递给Limit-JobWithTime
(包括如何从作业中获取输出的示例):< / strong>
#... 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?
答案 5 :(得分:0)
我想出了这个脚本。
代码:
Start-Transcript C:\Transcriptlog-Cleanup.txt #write log to this location
$p = Get-Process -Id $pid | select -Expand id # -Expand selcts the string from the object id out of the current proces.
Write-Host $p
$startTime = (Get-Date) # set start time
$startTime
$expiration = (Get-Date).AddSeconds(20) #program expires at this time
# you could change the expiration time by changing (Get-Date).AddSeconds(20) to (Get-Date).AddMinutes(10)or to hours whatever you like
#-----------------
#Timer update function setup
function UpdateTime
{
$LeftMinutes = ($expiration) - (Get-Date) | Select -Expand minutes # sets minutes left to left time
$LeftSeconds = ($expiration) - (Get-Date) | Select -Expand seconds # sets seconds left to left time
#Write time to console
Write-Host "------------------------------------------------------------------"
Write-Host "Timer started at : " $startTime
Write-Host "Current time : " (Get-Date)
Write-Host "Timer ends at : " $expiration
Write-Host "Time on expire timer : "$LeftMinutes "Minutes" $LeftSeconds "Seconds"
Write-Host "------------------------------------------------------------------"
}
#-----------------
do{ #start loop
Write-Host "Working"#start doing other script stuff
Start-Sleep -Milliseconds 5000 #add delay to reduce spam and processing power
UpdateTime #call upadate function to print time
}
until ($p.HasExited -or (Get-Date) -gt $expiration) #check exit time
Write-Host "done"
Stop-Transcript
if (-not $p.HasExited) { Stop-Process -ID $p -PassThru } # kill process after time expires