If you often use scripts utilizing Foreach loops, you’re going to want to read this. Serial execution of this sort of loop is commonplace. But, did you know, by utilizing workflows, you can execute a Foreach loop in parallel? By doing so, we can drastically reduce the execution time of a script because each item is taking place simultaneously rather than querying one after the other.
I recently had to use my hotfix-querying script (as discussed here: https://paytonflint.com/querying-systems-for-hotfix-patching-pro-tips/) to identify systems that had applied a particular hotfix after patching. I was working to identify the expected behavior of preview updates in Update Management, but I digress. I was unhappy with the script’s performance. For one, I wanted manageable .CSV output rather than writing to the console. But worst of all, querying one device at a time, the script took nearly half an hour to run. I knew I could do better.
I decided to have myself a little drag race between two scripts using parallel and serial execution respectively to see just how much I could improve execution time. I found this to be a formidable challenge – understanding the nuances of workflows, scope of variables, and the utilization of parameters are all items I had to figure out to create a script that would execute in parallel successfully.
I determined that, for a small group of 5 devices, there is not a huge difference between parallel and serial execution time. But, for 25 devices, parallelism executed almost twice as fast. For 200 devices, I found that parallel execution was almost five times faster. The more devices, the more pronounced the performance gain will become.
Alas, I arrived at the script below. If you are interested in working a script of your own to execute using parallelism, this will make a nice example.
# Script written by Payton Flint
# See https://paytonflint.com/parallel-vs-serial-execution-improving-powershell-script-performance/
# Parallel Execution:
# Set KB ID variable
$KBID = <Insert KBID>
# Identify location of script
$ScriptPath = Split-Path ($MyInvocation.MyCommand.Path) -Parent
# Set systems list location
$AllSystems = Get-Content "$ScriptPath\DeviceList.txt"
# KBIDQuery workflow
workflow KBIDQuery {
# Set workflow parameters
Param (
[string[]]$KBID,
[string[]]$ScriptPath,
[string[]]$AllSystems
)
# Parallel Foreach loop set to $Output to write to .CSV later
$Output = Foreach -Parallel ($system in $AllSystems) {
# InlineScript to use variables
inlinescript {
# Set compliance based on whether KBID is present on system
if ((Get-HotFix -ComputerName $Using:system).Where({$_.HotFixID -like $Using:KBID})){
$Compliance = $true
}
else{
$Compliance = $false
}
# Create table
[PSCustomObject]@{
Name = $Using:system
Length = $Compliance
}
}
}
# Write output to .CSV at parent directory
$Output | Export-Csv -Path "$ScriptPath\KBIDQueryParallelOutput.csv" -NoTypeInformation
}
# Call workflow
KBIDQuery -KBID $KBID -ScriptPath $ScriptPath -AllSystems $AllSystems
1 thought on “Parallel vs. Serial Execution – Improving PowerShell Script Performance”