ForEach vs foreach with PowerShell

How ForEach and foreach differ beyond just capital letters.

John Savill

March 1, 2016

2 Min Read
ForEach vs foreach with PowerShell

Q. Understand the difference between ForEach and foreach?

A. PowerShell has two different ForEach's. The first is a cmdlet named ForEach-Object that is part of the Microsoft.PowerShell.Core module. Thie cmdlet loops through the objects and performs code in the scriptblock and references the passed objects as $_. For example:

$names = @("Julie","Abby","Ben","Kevin")
$names | ForEach-Object -Process { Write-Output $_}

Note that two aliases exist for ForEach-Object; ForEach and % and you may see either. The equivalent of the above could be:

$names | ForEach -Process { Write-Output $_}

$names | ForEach { Write-Output $_}

$names | % { Write-Output $_}

The other type of foreach is a statement that once again processes each object in a collection  and performs the code in the scriptblock for each item but this time a specific name is used to reference each item in the collection. An example is:

foreach ($name in $names) { Write-Output $name}

Note that the outcome is the same, the objects in a collection are looped through one at a time. So what is the difference? Typically the foreach statement is faster since it gets compiled to a single expression where as foreach-object compiles to multiple expressions however a potential downside of the foreach statement is because it is a single expression the entire collection must be stored in memory whereas with the foreach-object data is loaded into memory as needed. Loading everything into memory first may still be faster overall but means more memory will be used and required.

You can see this in action that foreach statement loads everything into memory first by trying to recurse every file in the Windows folder. When you run the code below there is an initial delay as every item is loaded before output to screen.

foreach ($file in (Get-ChildItem C:Windows -Recurse)) {$file.Name}

This contrasts with the same code using the ForEach-Object which starts output to screen straight away.

Get-ChildItem C:Windows -Recurse | ForEach-Object {$_.Name}

The total time though is still faster with foreach statement (but would use more memory).

$Time1 = (Measure-Command {Get-ChildItem C:Windows -Recurse | ForEach-Object {$_.Name}}).TotalMilliseconds$Time2 = (Measure-Command {foreach ($file in (Get-ChildItem C:Windows -Recurse)) {$file.Name}}).TotalMillisecondsWrite-Output "Time using ForEach-Object is $Time1"Write-Output "Time using ForEach statement is $Time2"Time using ForEach-Object is 16617.7766Time using ForEach statement is 15433.7096

 

About the Author

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like