Powershell – ForEach-Parallel


In PowerShell I often find the need to speed things up when having to do querying lots of similar things – usually getting the same stuff from multiple machines. So I ventured out onto the Interwebs and over time slap together a PowerShell module that does parallel processing. I’m not claiming this to be purely my work – I only added and refined it a bit for my needs.

This example works with ‘older’ versions of PowerShell (think version 4/5 and perhaps 3). The latest versions of PowerShell (afaik version 7) now has something like this built in.


Using any sort of parallel coding requires a different approach than normal procedural (Start at the top and run code line by line until you get to the end). Basically it is multi-threading but PowerShell ‘out of the box’ has nothing like it. To implement multi threading you need to use ‘runspaces’ which effectively means you are running multiple instances of PowerShell.

The ForEach-Parallel function takes a scriptblock as input. Optionally you can also specify the number of threads used to do the parallel processing.

function ForEach-Parallel {
         [System.Management.Automation.ScriptBlock] $ScriptBlock,
     BEGIN {
         $iss = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
         $pool = [Runspacefactory]::CreateRunspacePool(1, $maxthreads, $iss, $host)
         $threads = @()
         $ScriptBlock = $ExecutionContext.InvokeCommand.NewScriptBlock("param($_)r`n" + $Scriptblock.ToString())
     PROCESS {
         $powershell = ::Create().addscript($scriptblock).addargument($InputObject)
         $threads+= @{
             instance = $powershell
             handle = $powershell.begininvoke()
     END {
         $notdone = $true
         while ($notdone) {
             $notdone = $false
             for ($i=0; $i -lt $threads.count; $i++) {
                 $thread = $threads[$i]
                 if ($thread) {
                     if ($thread.handle.iscompleted) {
                         $threads[$i] = $null
                     else {
                         $notdone = $true
 export-modulemember -function ForEach-Parallel 

To make use of this ‘module’ save it to a file named ForEach-Parallel.psm1 and place it in C:\Users\{your user account}\Documents\WindowsPowerShell\modules\ForEach-Parallel


$computers = 'computer1','computer2','computer3'
 $computers | ForEach-Parallel -MaxThreads 20 -ScriptBlock {
     $computerToPing = $_
     [int]$ResponseTime = 0
     [string]$ResolvedName = ''
     $StepPing = (Test-Connection -ComputerName $computerToPing -Count 1 -ErrorAction SilentlyContinue)
   if ($StepPing -ne $null){
      $ResponseTime = $StepPing.ResponseTime 
   New-Object psobject -Property @{     
    Name               = $computerToPing     
    ResponseTime       = $ResponseTime                  


There are a few things to watch out for – like any multi-threading coding. While the code is running there is no indication how far each ‘thread’ is – you have to wait until all of them are done. Threads are independent so they cannot reference each other or even variables in the calling thread.

So.. happy multi-threading.

Leave a Reply

%d bloggers like this: