Queuing reboots em Powershell

5

Estou trabalhando em um projeto para reinicializar uma grande quantidade de computadores. Um dos requisitos importantes é preparar as reinicializações para que todas as máquinas não sejam reinicializadas de uma vez (muito rápido e causará problemas na SAN).

Eu tentei fazer isso em um fluxo de trabalho acelerando para 50 ações paralelas e adicionando um atraso de 15 segundos (200 reinicializações por minuto).

workflow Bounce-Computer {
param(
[string[]]$Computers
)
foreach -parallel -throttlelimit 50 ($computer in $Computers) {
    Restart-Computer -PSComputerName $computer -Force
    Start-Sleep -Seconds 15
    }
}

Mas me deparei com um problema em que o fluxo de trabalho seria interrompido se o WMI fosse quebrado em um computador de destino.

Fora de consertar o WMI em todas as máquinas de destino (existem vários milhares), como eu faria algo assim de maneira controlada? Empregos?

    
por Acerbity 09.04.2015 / 21:16

4 respostas

0

Acabei de reescrever o script para usar o VIC. O WMI neste ambiente era instável demais para ser usado.

    
por 07.08.2015 / 16:38
0

Acho que há mais de uma maneira de resolver seu problema, pelo menos pelo que vejo como a causa. Aqui está como eu faria:

Workflow Invoke-MassRestart{
    Param
    (
        [parameter(mandatory=$true,
                   ValueFromPipelineByPropertyName=$true)]
        [string[]]
        $ComputerName,

        [int]
        $Throttle = 5,

        [int]
        $Delay = 5
    )

    Foreach -parallel -ThrottleLimit $Throttle ($Computer in $ComputerName){
        Sequence {
            InlineScript{
                [void](Restart-Computer -PSComputerName $using:Computer)
            }
            Start-Sleep -Seconds $Delay
        }
    }
}

Deixe-me saber se há alguma parte disso que você quer que eu explique. Gostaria de chamar minha transmissão de Restart-Computer para o [void] . Isso basicamente diz ao sistema para emitir o comando e seguir em frente. Eu acho que você estava sendo lavado quando estava esperando por 50 operações para relatar algum tipo de status. Observe também o escopo exclusivo necessário dentro do bloco InlineScript{} . Eu também decidi fazer isso para que ele pudesse aceitar entrada de pipeline de Get-ADComputer .

    
por 09.04.2015 / 23:09
0

Sem retrabalhar seu script em demasia, você pode deixar o script detectar o erro de tempo limite do WMI (se ele gerar um erro durante o travamento) e reinicializar o próximo computador. A instrução catch pode gerar o problema e o erro do computador para você revisar mais tarde.

Workflow Bounce-Computer {
 param([string[]]$Computers)
 foreach -parallel -throttlelimit 50 ($computer in $Computers) {
    try{
        Restart-Computer -PSComputerName $computer -Force -ErrorAction stop
        Start-Sleep -Seconds 15
    } 
    catch [AppropriateWMIExceptionError]
    { 
       echo 'WMI timeout error' #Or another action to note the problem computer
    }
}
    
por 13.04.2015 / 19:38
0

Eu usaria o mecanismo de trabalho e faria algo como abaixo. Isso não é totalmente testado, mas deve funcionar pode ter perdido algo em algum lugar.

Dessa forma, você também faz com que eles sejam executados em paralelo e, se um reinício travar, é apenas esse trabalho que leva tempo e, se um trabalho levar muito tempo, removemos esse trabalho.

Código abaixo:

function restart-myComputer (
[Parameter(ParameterSetName="restart", Mandatory=".")]
[Parameter(ParameterSetName="bg", Mandatory=".")]
[string]$computer,
[Parameter(ParameterSetName="restart")]
[int]$wait,
[Parameter(ParameterSetName="bg")]
[switch]$bg)
{ 
  if ($bg) {
    Start-Job -name $computer -ScriptBlock ([scriptblock]::create("Restart-Computer -PSComputerName $computer -Force -ErrorAction stop")) > $null
  } else {
    Restart-Computer -PSComputerName $computer -Force -ErrorAction stop
    Start-Sleep -Seconds $wait
  }
}

function remove-myJobs (
[Parameter(ParameterSetName="remove")]
[string[]]$names,
[Parameter(ParameterSetName="remove")]
[int]$maxRunTime = 30
{
  $d = get-date
  [string[]]$stillRunningJobArr = @()
  foreach ($name in $names) {
    $job = get-job -name $name 
    $diffTime = $d - $job.PSBeginTime
    if($diffTime.TotalSeconds -gt $maxRunTime) {
      remove-job -name $name -Force
      write-host "Removed job $name that ran longer then $maxRunTime seconds"
    } else {
      write-host "Job $name has still not been running for more then $maxRunTime"
      $stillRunningJobArr += $name
    }
  }
  return $stillRunningJobArr
}

function remove-allMyJobs (
[Parameter(ParameterSetName="remove")]
[int]$maxRunTime = 30)
{
  $d = get-date
  foreach ($job in get-job) {
    $diffTime = $d - $job.PSBeginTime
    $name = $job.name

    if($diffTime.TotalSeconds -gt $maxRunTime) {
      remove-job -name $name -Force
      write-host "Removed job $name that ran longer then $maxRunTime seconds"
    } else {
      write-host "Job $name has still not been running for more then $maxRunTime"
    }
  }
}

function restart-myComputers (
[Parameter(ParameterSetName="restart", Mandatory=".")]
[Parameter(ParameterSetName="bg", Mandatory=".")]
[string[]]$computers,
[Parameter(ParameterSetName="bg", Mandatory=".")]
[int]$maxConcurrentJobs,
[Parameter(ParameterSetName="bg", Mandatory=".")]
[Parameter(ParameterSetName="restart")]
[int]$wait,
[Parameter(ParameterSetName="bg")]
[switch]$bg)
{
  [string[]]$restartedComputerArr = @()
  if ($bg) {
    foreach ($computer in $computers) {
      if((get-job -state 'Running').Count -gt $maxConcurrentJobs) {
        $restartedComputerArr = stop-myJobs -$restartedComputerArr -maxRunTime $maxRunTime
        sleep $wait # Wait to get as many jobs to complete as possible.
      }
      Restart-myComputer -computer $computer -bg
      $restartedComputerArr += $computer
    }
  } else {
    Restart-myComputer -computer $computer -wait $wait
  }
  remove-allMyJobs
}
    
por 07.08.2015 / 12:42

Tags