98 lines
3.4 KiB
PowerShell
98 lines
3.4 KiB
PowerShell
function Invoke-ParallelServers {
|
|
<#
|
|
.SYNOPSIS
|
|
Executes a script block against a list of servers in parallel with PSJobs + remote sessions.
|
|
Can return results if the ReturnObjects switch is supplied
|
|
|
|
.PARAMETER Servers
|
|
[string[]] List of fully qualified server addresses to apply this across
|
|
|
|
.PARAMETER Script
|
|
[ScriptBlock] The scriptblock to execute
|
|
|
|
.PARAMETER Arguments
|
|
[object[]] The arguments to be passed into the inner scriptblock
|
|
|
|
.PARAMETER NumThreads
|
|
[int] Defualts to 30
|
|
|
|
.PARAMETER ReturnObjects
|
|
[switch] Do we return results after the run? Legacy functionality is to swallow the Write-Output and return $XYZ values. Other "return" values like Write-Host streams continue to be returned in either option.
|
|
|
|
.NOTES
|
|
The arguments are passed to each job globally. If you want to pass different arguments to different jobs, format it into the object[] list argument.
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory=$true)]
|
|
[string[]]$Servers,
|
|
|
|
[Parameter(Mandatory=$true)]
|
|
[object]$Script,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[object[]]$Arguments = $null,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[int]$NumThreads = 30,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$ReturnObjects
|
|
)
|
|
process {
|
|
$jobs = @()
|
|
|
|
# Define script block to create remote session, and execute the script block parameter on the remote host.
|
|
$ScriptBlock = {
|
|
param($server, $innerScript, $passedArguments)
|
|
process {
|
|
|
|
$remoteBlock = [scriptblock]::Create($innerScript)
|
|
|
|
$session = New-PSSession $server -ErrorAction SilentlyContinue
|
|
if($session.ComputerName -ne $server)
|
|
{
|
|
throw "Could not connect to $server"
|
|
}
|
|
|
|
return Invoke-Command -Session $session -ScriptBlock $remoteBlock -ArgumentList $passedArguments
|
|
}
|
|
end
|
|
{
|
|
Remove-PSSession $session
|
|
}
|
|
}
|
|
|
|
$logLead = (Get-LogLeadName);
|
|
|
|
# For each server.
|
|
foreach($server in $Servers)
|
|
{
|
|
Write-Verbose ("$logLead : Starting job for host {0}" -f $server)
|
|
$jobs += Start-Job -ScriptBlock $ScriptBlock -ArgumentList $server,$Script,$Arguments
|
|
|
|
$running = @($jobs | Where-Object {$_.State -in ('Running','NotStarted')})
|
|
|
|
while ($running.Count -ge $NumThreads -and $running.Count -ne 0)
|
|
{
|
|
(Wait-Job -Job $jobs -Any) | Out-Null
|
|
$running = @($jobs | Where-Object {$_.State -in ('Running','NotStarted')})
|
|
}
|
|
}
|
|
|
|
(Wait-Job -Job $jobs) | Out-Null
|
|
|
|
$results = @()
|
|
# Receive-Job to output the logs.
|
|
# SRE-13225 - Receive-Job dumps all of the output streams from a job to the current PS "host"
|
|
# When one of those is an "error" it stops because our $ErrorActionPreference is "Stop"
|
|
# To get all of the output from these parallelized jobs, we need to "Continue"
|
|
# All the jobs have already finished executing at this point. This does not alter that.
|
|
# This merely allows us to see all of the output (unless there's a throw?)
|
|
$jobs | ForEach-Object { $results += (Receive-Job -Job $_ -ErrorAction Continue) }
|
|
|
|
if($ReturnObjects) {
|
|
return $results
|
|
}
|
|
}
|
|
}
|