Вопрос

Я пытаюсь выполнить функцию или сценарий в 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 Runspaces:

http://learn-powershell.net/2012/05/13/using-background-runspaces-instead-of-psjobs-for-better-performance/

Другие советы

Сегодня я столкнулся с аналогичным вопросом и заметил, что на этот вопрос не было фактического ответа. Я создал простой класс 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top