Parallel Loops for Windows PowerShell

Listen to this blog post!

Table of contents:

Previously, we looked at parallel loops. They were introduced in PowerShell 7 and are not available in Windows PowerShell. However, it is entirely possible to add them to Windows PowerShell manually.

One of the best modules for this is PSParallel, which is available on the PowerShell Gallery. You can install it simply:

Install-Module -Name PSParallel -Scope CurrentUser 

Now you have access to a new cmdlet, Invoke-Parallel. It works just like the parallel loop built into PowerShell 7. Let’s adapt the super-fast range ping from our previous post for Windows PowerShell:

1..254 | Invoke-Parallel {
  # defining custom functions per thread
  function Ping-Computer {
    param
    (
      [Parameter(ValueFromPipeline, Mandatory)]
      [string]
      $ComputerName,

      # timeout in milliseconds
      [int]
      $Timeout = 5000
    )

    begin {
      $obj = [System.Net.NetworkInformation.Ping]::new()
    }
    process {
      $obj.Send($ComputerName, $timeout) |
        Select-Object -Property Status, Address, RoundTripTime, Success |
        ForEach-Object {
          # fill in the computername/IP address in case there was
          # no response
          $_.Address = $ComputerName
          # add a Boolean value
          $_.Success = $_.Status -eq [System.Net.NetworkInformation.IPStatus]::Success
          $_
        }
      }
      end {
        $obj.Dispose()
      }
    }

    # running  the task in parallel
    # MAKE SURE TO ADJUST THE IP ADDRESS TO MATCH YOUR NETWORK!
    $ip = "192.168.2.$_"
    Ping-Computer -ComputerName $ip -Timeout 500
} -ThrottleLimit 128

IMPORTANT: Change the variable $ip if you want to ping a different IPv4 range. The provided code pings addresses from 192.168.2.1 to 192.168.2.254.

Code Differences

The differences between Windows PowerShell and PowerShell 7 are minimal:

  • In PowerShell 7, parallel looping is integrated into the existing ForEach-Object cmdlet.
  • In Windows PowerShell, the community couldn’t do this, so they created cmdlets like Invoke-Parallel specifically for parallel looping. In PowerShell 7, you use ForEach-Object -Parallel; in Windows PowerShell, you use Invoke-Parallel.

There are a few implementation differences as well:

  • Invoke-Parallel shows progress bars by default, which can be very helpful to understand what the loop is doing. If you don’t want progress bars, add the switch parameter -NoProgress.
  • Real-time results: ForEach-Object -Parallel returns results from its threads immediately, whereas Invoke-Parallel waits for all threads to finish before returning results. Overall performance is comparable.

Related links