If you’ve been around PowerShell for a while, you know it’s great at looping through stuff. Need to process a list of files? Easy. Query a set of servers? Piece of cake. But sometimes… you hit a wall. The problem? Sequential execution.

By default, your loops work in a single-file line, like shoppers at a small-town bakery. That’s fine for five people. Not so fine for five thousand.

That’s where ForEach-Object -Parallel enters the chat.

🚀 This feature, introduced in PowerShell 7, lets you process multiple items at the same time, tapping into all those CPU cores just sitting there looking bored.

I’ve made a post about this earlier, on how to speed-up your scripts by going in-depth. This one will stay native with the PowerShell 7 way forward. If you are interested you can find the post here:

Today, we’re going to walk through how it works, why it’s a game-changer, and where you should (and shouldn’t) use it. We’ll keep it hands-on, so keep PowerShell open!

you’ll see the 🎬 icon whenever it’s time to get your hands dirty.

Today’s Toolbelt

Here’s the deal:

ForEach-Object -Parallel is like the express checkout lane at the grocery store. Instead of every task waiting for the one ahead to finish, they all get their own lane. (also as shown in my previous post with the ‘highway metaphor’:

We’ll explore:

  • Basic parallel loops – Using ForEach-Object -Parallel in the simplest form
  • Passing variables – How to get data into your parallel script block
  • Controlling thread counts – Because unlimited parallelism can get… messy
  • Real-world scenarios – Places where it shines (and where it doesn’t)

Why Parallel?

Imagine you have 50 servers to check for a certain log file. Running them one after another takes… forever. With parallel processing, you can hit multiple servers at once, finishing in a fraction of the time.

📒 Under the hood: PowerShell spins up runspaces, lightweight, isolated environment, to execute each chunk of work simultaneously. It’s not “true” OS-level multithreading, but it’s incredibly efficient for I/O-bound tasks like network calls, file reads, or API requests.

1..5 | ForEach-Object -Parallel {
    Start-Sleep -Seconds 1
    "Task $_ completed on thread $([System.Threading.Thread]::CurrentThread.ManagedThreadId)"
}

What’s happening:

1..5 gives us five items.

Each item is processed in a parallel runspace.

They all sleep for one second…. 🥁🥁🥁 but because they run in parallel, the whole thing finishes in just over a second, not five!

Passing Data Into Parallel Blocks

One catch with ForEach-Object -Parallel: it runs in its own scope. Your outer variables aren’t magically available inside.

🎬 Here’s how to pass variables in:

$prefix = "Server"

1..3 | ForEach-Object -Parallel {

    "$using:prefix-$($_)"

}

📒 The magic word: $using: tells PowerShell to bring in a variable from outside the parallel block.

Controlling the Chaos

Yes, parallelism is powerful, but if you let 200 jobs spin up at once, you might as well be starting a tiny CPU apocalypse 💣.

🎬 Throttle it with

1..10 | ForEach-Object -Parallel {

    Start-Sleep -Seconds 2

    "Processed $_"

} -ThrottleLimit 3

Here, only three parallel tasks run at a time. As soon as one finishes, the next starts.

Real-World Example: Network Ping

🎬 Checking multiple hosts in parallel:

$servers = "server1","server2","server3","server4","server5"

$servers | ForEach-Object -Parallel {

    $result = Test-Connection -ComputerName $_ -Count 1 -Quiet

    "$_ is " + ($(if ($result) { "online" } else { "offline" }))

} -ThrottleLimit 2
  • The pings happen two at a time.
  • Overall time drops drastically compared to running sequentially.

When Not to Use It

📒 Parallelism is not a free lunch.

  • If your task is super short and light (like adding numbers), spinning up runspaces is actually slower.
  • For CPU-heavy operations, you might saturate your system quickly.
  • Avoid it when order matters, parallel execution doesn’t guarantee output order unless you take extra steps.

Summary

Wrapping It Up! PowerShell Meets Parallelism 🎉

Today we saw how ForEach-Object -Parallel lets you take PowerShell’s already-great iteration abilities and put them into warp speed.

We covered:

  • The basics of parallel loops
  • Passing variables with $using:
  • Throttling to keep your system happy
  • Real-world use cases like pinging servers

The takeaway? When you’re faced with a big list of time-consuming tasks, don’t just wait your turn in the single checkout lane. Open more lanes with ForEach-Object -Parallel! Just remember that more isn’t always better.

Got your own clever use for parallel loops? Share it, I love seeing how people bend PowerShell to their will. And don’t forgot to check my previous post which dives into how too do it from older PowerShell versions and create your own threadpools!

Until next time! Keep automating, keep experimenting, and keep pushing your scripts to

the next level. 🚀☕🍰

Leave a Reply

Your email address will not be published. Required fields are marked *