Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Archives
April 14, 2026

Faster ForEaching

In this issue:

  • ForEach()
  • Arguments
  • Faster Combos
  • Limitations
  • Summary

Last time, I showed you how to take advantage of a method that PowerShell inserts into collections. The Where() method provides an often faster solution instead of piping objects to Where-Object. If nothing else, it provides a compact form that lends itself to a one-line command.

ForEach()

The other method that PowerShell adds to collections is Foreach(). This behaves the same way as the ForEach-Object cmdlet: do something to each thing in the collection. Let's start with a very basic example. Here's the traditional pipelined approach:

1..5000 | ForEach-Object {($_*$_)*[math]::pi}

For each number between 1 and 5000, perform a calculation. This takes about 47ms for me. The alternative using the method looks like this:

(1..5000).ForEach({($_*$_)*[math]::pi})

Remember, PowerShell needs a collection. I'm not using the pipeline here. PowerShell executes the code in the parentheses to define the collection, then invokes the ForEach() method. This took about 25ms to complete. I still use a scriptblock inside the method.

To be fair, we should also look at the ForEach keyword.

foreach ($i in (1..5000)) {
    ($i*$i)*[math]::pi
}

This too is processing the collection and not really using the pipeline. In this scenario, using the ForEach keyword is even faster. However, there may be more to your work than mere speed. The right approach may depend on how your code relates to other parts of your PowerShell expression. The ForEach() method was intended to process DSC configuration data files very quickly without having to write a pipelined expression.

But we can take advantage of the method in the PowerShell console.

PS C:\> (dir c:\work -Directory).foreach({$stat = Get-ChildItem $_ -file -recurse | Measure-Object length -sum; [PSCustomObject]@{Path = $_.FullName;Files = $stat.count;Size = $stat.sum}})

Path                            Files        Size
----                            -----        ----
C:\work\DSCModule                   9     5584.00
C:\work\foobar                      0
C:\work\Hicks-PowerShell-Live       6   366103.00
C:\work\ironscripter               41    69544.00
C:\work\Microsoft.Winget.Client    35 46730337.00
C:\work\samples                     2    47124.00
C:\work\stuff                       4   830140.00
C:\work\temp                        2  8912657.00
C:\work\watch                       2      927.00

This is handy for ad-hoc testing or prototyping. It wouldn't take much work to transform the script block in the ForEach() method into a function that accepts pipeline input.

Want to read the full issue?
GitHub
Bluesky
LinkedIn
Mastodon
jdhitsolutions.github.io
Powered by Buttondown, the easiest way to start and grow your newsletter.