So, I had a scenario the other day where I wanted to run a PowerShell script on approximately 300 remote computers in an outage windows of no more than 30 minutes. The challenge was the script took 2 minutes to complete. I didn’t have enough fingers and toes for the math, so used a calculator to determine it would be… 600 minutes. Hmm, last time I checked 600 minutes is more than 30. So what to do..
The only way I could see this getting across the line was doing things in parallel. At 2 minutes per computer, I would need… give me a second… 20! batches of 15 computers. That would allow me to knock it out in 30 minutes. Well that was great, how was I going to do that? Also, with all things I do, I wanted to make the script reusable.
Now there are numerous ways to attack this, PowerShell workflows or jobs for example, but I also wanted to see output on screen as it was running. So I needed to launch separate PowerShell consoles for each of my batches of scripts. Without further ado here is what was cobbled together:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# Take a few parameters # ComputerName - 1 or more computers (obviously pass more than one! or whats the point??) # ScriptPath - Path to the PS1 powershell script you want to execute # Batches - Number of Computers you want to pass to each Powershell script specified (default 10) function Start-MultipleScriptExecution ($ComputerName, $ScriptPath, $Batches=10) { #Break the passed Computers into their batches for ($i = 0; $i -lt ($ComputerName.Length)/$Batches; $i++) { #Create an array to hold the computers in each batch $Batch = @() for ($j = 0; $j -lt $Batches; $j++) { # Get index of computer to retrieve from array $index = ($Batches * $i) + $j # Ensure index is not greater than array length if ($index -lt $ComputerName.Length) { #add computer to batch $Batch += $ComputerName[$index] } } # Join the batch array of computers together with commas $BatchArg = [String]::Join(",",$Batch) # Create arguments, NOTE the script that is called needs to load an argument # called "Batch" that will contain the computers in it's batch $args=" -NoExit -File $ScriptPath -Batch $BatchArg" # Start new instance of Powershell with given computers and do it all again (i.e. loop) Start-Process "powershell.exe" -ArgumentList $args } } # Job Done |
Enjoy, pretty hacky, but that’s the way i roll!