When you're managing thousands of systems, checking for patch compliance across all of them can become a real slog, especially if you’re still looping through them sequentially or juggling a pile of background jobs. That used to be me.
Recently, I rewrote one of my older patch check scripts using PowerShell 7’s ForEach-Object -Parallel
feature, and the results were night and day. Here’s a look at how I did it and why you might want to make the leap, too.
The Legacy Job-Based Approach (Worked... but Clunky)
$servers = Get-Content .\serverlist.txt
$jobs = foreach ($server in $servers) {
Start-Job -ScriptBlock {
$s = $using:server
Invoke-Command -ComputerName $s -ScriptBlock {
Get-HotFix -Id KB5008380
}
}
}
# Wait and collect
$results = $jobs | Wait-Job | ForEach-Object {
Receive-Job -Job $_
}
It got the job done, but there was too much scaffolding: tracking, collecting, cleaning up jobs, and dealing with throttling manually.
Enter PowerShell 7: A One-Liner Game Changer
$servers = Get-Content .\serverlist.txt
$results = $servers | ForEach-Object -Parallel {
try {
Invoke-Command -ComputerName $_ -ScriptBlock {
Get-HotFix -Id KB5008380
}
[PSCustomObject]@{ Server = $_; Patched = $true }
}
catch {
[PSCustomObject]@{ Server = $_; Patched = $false }
}
} -ThrottleLimit 10
- ✔️ Built-in throttling
- ✔️ Fewer moving parts
- ✔️ Much easier to maintain and explain to others
And yes—runtime improved significantly when scaled out.
Bonus: Reporting
You can easily integrate this with your preferred reporting pipeline—CSV, HTML, or even Power BI. Here's a quick CSV export:
$results | Export-Csv .\PatchResults.csv -NoTypeInformation
Final Thoughts
The job-based model served us well, but with PowerShell 7's baked-in parallelism, most of my automation scripts just got faster and cleaner. This is one of those “glad I made the switch” moments—especially when time-to-resolution matters.
Have you tried this approach yet? I’d love to hear how you're using -Parallel
in your environment.
No comments:
Post a Comment