我正在尝试在powershell中执行函数或脚本块,并为执行设置超时。
基本上我有以下内容(翻译成伪代码):
function query{
#query remote system for something
}
$computerList = Get-Content "C:scriptscomputers.txt"
foreach ($computer in $computerList){
$result = query
#do something with $result
}
查询的范围可以从使用 Get-WmiObject 的 WMI 查询到 HTTP 请求,并且脚本必须在混合环境中运行,其中包括并非都具有 HTTP 接口的 Windows 和 Unix 计算机。因此,某些查询必然会挂起或需要很长时间才能返回。在寻求优化的过程中,我写了以下内容:
$blockofcode = {
#query remote system for something
}
foreach ($computer in $computerList){
$Job = Start-Job -ScriptBlock $blockofcode -ArgumentList $computer
Wait-Job $Job.ID -Timeout 10 | out-null
$result = Receive-Job $Job.ID
#do something with result
}
但不幸的是,工作似乎承担了很多开销。在我的测试中,一个在 1.066 秒内执行的查询(根据 $blockofcode 内部的计时器)在作为作业执行时需要 6.964 秒才能返回结果。当然它有效,但我真的很想减少开销。我也可以一起启动所有工作,然后等待它们完成,但工作仍然可能挂起或花费大量时间才能完成。
因此,关于这个问题:有没有办法执行语句、函数、脚本块甚至超时的脚本,而超时不包括作业带来的那种开销?如果可能的话,我想并行运行命令,但这不是一个交易破坏者。
任何帮助或提示将不胜感激!
编辑:在混合窗口/Unix环境中运行Powershell V3
今天,我遇到了一个类似的问题,并注意到这个问题没有实际答案。我创建了一个简单的PowerShell类,称为TimedScript
。此类提供以下功能:
-
方法:
Start()
准备好时开始工作的方法 -
方法:
GetResult()
方法,检索脚本的输出
构造函数: - 采用两个参数的构造函数:
- 要执行的
ScriptBlock
-
[int]
超时期限(以毫秒为单位)
- 要执行的
它目前缺少:
- 将参数传递给 PowerShell ScriptBlock
- 您想到的其他有用功能
类: 定时脚本
class TimedScript {
[System.Timers.Timer] $Timer = [System.Timers.Timer]::new()
[powershell] $PowerShell
[runspace] $Runspace = [runspacefactory]::CreateRunspace()
[System.IAsyncResult] $IAsyncResult
TimedScript([ScriptBlock] $ScriptBlock, [int] $Timeout) {
$this.PowerShell = [powershell]::Create()
$this.PowerShell.AddScript($ScriptBlock)
$this.PowerShell.Runspace = $this.Runspace
$this.Timer.Interval = $Timeout
Register-ObjectEvent -InputObject $this.Timer -EventName Elapsed -MessageData $this -Action ({
$Job = $event.MessageData
$Job.PowerShell.Stop()
$Job.Runspace.Close()
$Job.Timer.Enabled = $False
})
}
### Method: Call this when you want to start the job.
[void] Start() {
$this.Runspace.Open()
$this.Timer.Start()
$this.IAsyncResult = $this.PowerShell.BeginInvoke()
}
### Method: Once the job has finished, call this to get the results
[object[]] GetResult() {
return $this.PowerShell.EndInvoke($this.IAsyncResult)
}
}
TimedScript 类的示例用法
# EXAMPLE: The timeout period is set longer than the execution time of the script, so this will succeed
$Job1 = [TimedScript]::new({ Start-Sleep -Seconds 2 }, 4000)
# EXAMPLE: This script will fail. Even though Get-Process returns quickly, the Start-Sleep call will cause it to be terminated by its Timer.
$Job2 = [TimedScript]::new({ Get-Process -Name s*; Start-Sleep -Seconds 3 }, 2000)
# EXAMPLE: This job will fail, because the timeout is less than the script execution time.
$Job3 = [TimedScript]::new({ Start-Sleep -Seconds 3 }, 1000)
$Job1.Start()
$Job2.Start()
$Job3.Start()
代码也托管在GitHub Gist上。
我想你可能想使用Powershell运行空间进行调查:
http://learn-powershell.net/2012/05/13/using-background-runspaces-instead-of-psjobs-for-better-performance/