Я думаю, вы можете исследовать, используя PowerShell Runspaces:
PowerShell Timeout
-
29-07-2022 - |
Вопрос
Я пытаюсь выполнить функцию или сценарий в PowerShell и установить тайм -аут для выполнения.
В основном у меня есть следующее (переведено на псевдокод):
function query{
#query remote system for something
}
$computerList = Get-Content "C:\scripts\computers.txt"
foreach ($computer in $computerList){
$result = query
#do something with $result
}
Запрос может варьироваться от запроса WMI с использованием get-wmiobject до HTTP-запроса, а скрипт должен работать в смешанной среде, которая включает в себя машины Windows и Unix, которые не все имеют интерфейс HTTP. Следовательно, некоторые из запросов обязательно будут зависеть или займет очень много времени, чтобы вернуться. В моем стремлении к оптимизации я написал следующее:
$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 секунды, чтобы вернуть результат при выполнении в качестве задания. Конечно, это работает, но я бы очень хотел уменьшить эти накладные расходы. Я также мог бы начать все работы вместе, а затем подождать, пока они закончат, но задания все еще могут повесить или занять нелепое количество времени, чтобы завершить.
Итак, к вопросу: есть ли способ выполнить оператор, функцию, сценарий или даже сценарий с тайм -аутом, который не содержит такого рода накладных расходов, которые поставляются с заданиями? Если возможно, я хотел бы запустить команды параллельно, но это не нарушитель сделки.
Любая помощь или подсказки были бы очень оценены!
РЕДАКТИРОВАТЬ: Запуск PowerShell V3 в смешанной среде Windows/Unix
Решение 2
Другие советы
Сегодня я столкнулся с аналогичным вопросом и заметил, что на этот вопрос не было фактического ответа. Я создал простой класс PowerShell, называемый TimedScript
. Анкет Этот класс предоставляет следующую функциональность:
- Метод:
Start()
метод для начала работы, когда вы будете готовы - Метод:
GetResult()
Метод, чтобы получить вывод сценария - Конструктор: Конструктор, который принимает два параметра:
ScriptBlock
выполнить[int]
период времени, в миллисекундах
В настоящее время не хватает:
- Передача в аргументах в сценарий PowerShell
- Другие полезные функции, которые вы думаете
Класс: TimeedScript
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)
}
}
Пример использования класса TimeedScript
# 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.