在PowerShell中排队重启

我正在开发一个重启大量计算机的项目。 其中一个重要的要求是重新启动,以便所有机器不会立即重新启动(速度太快,会导致SAN问题)。

我试图通过限制50个并行操作并添加15秒的延迟(每分钟200次重启)来尝试在工作stream中执行此操作。

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

但是我遇到了一个问题,如果WMI在目标计算机上被破坏,工作stream程将会挂起。

除了在所有目标机器(有几千个)上修复WMI之外,我将如何以受控的方式去做这样的事情呢? 工作?

我认为,解决问题的方法不止一种,至less从我认为的原因来看。 以下是我该怎么做:

 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 } } } 

让我知道是否有任何这个部分你想我解释。 我想叫我的Restart-Computer铸造到[void] 。 这基本上告诉系统发出命令并继续前进。 我想你在等待50个行动来报告某种状态的时候会变得一团糟。 还要注意InlineScript{}块中需要的唯一范围。 我也决定让它可以接受来自Get-ADComputerstream水线input。

如果没有太多重写脚本,可以让脚本捕获WMI超时错误(如果在挂起过程中抛出可捕获的错误),然后重新启动下一台计算机。 catch语句可以输出问题的计算机和错误供您稍后查看。

 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 } } 

我会使用工作引擎,而不是像下面这样做。 这没有完全testing,但它应该工作可能已经错过了某个地方。

这样,你也可以让他们并行运行,如果一次重新启动,只是这个工作需要时间,如果一个工作需要很长时间,我们删除这个工作。

代码如下:

 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 } 

我最终重写了使用VIC的脚本。 这个环境中的WMI太不稳定了,无法使用。