PowerShell Foreach vs ForEach-Object

8 Nov

There are two variants of ‘for each’ in PowerShell:
Foreach statement: iterates over a collection of objects
ForEach-Object: obtains its entries from the pipeline

At first they both seemed to do the job, but there are some differences.
Let’s do a test with a simple array of items and loop through it using both foreach methods. To measure the time elapsed to loop the array the Measure-Command is used.



$items = 1,2,3,4,5,6,7,8,9,0,10,12,13,14,15,52,58,41,59,841,5,4,1

Write-Host "ForEach-Object: "
(Measure-Command {  `
 $items | ForEach-Object { `
  "Item: $_" `
 }}).totalmilliseconds

Write-Host "Foreach: "
(Measure-Command {  `
 Foreach ($item in $items) { `
  "Item: $element" `
 }}).totalmilliseconds

Multiple results:

The results differ a lot!

When to use which method?

When the items of the array are known at forehand, like in the test, foreach is the better approach because of the speed. This kind of speed can only be reached when all the objects are already known and stored in a variable.

ForEach-Object is a different story. When the items have to be collected before the loop starts and this can take a while: use ForEach-Object.
This method processes the objects collected in the array directly when available and doesn’t wait until all objects are collected.

10 Replies to “PowerShell Foreach vs ForEach-Object

  1. Another important difference is that Foreach doesn’t write to the pipeline. A command like this will fail:

    foreach ($x in (1..10)) {$x*2} | out-file test.txt

    But this will work:

    1..10 | foreach-object {$_*2} | out-file test.txt

    I think of the former foreach as a legacy or transition for people coming from the VBScript world. That said, both approaches are valid. You have to figure out your larger context and see which makes sense.

  2. I’m new to Powershell, but couldn’t you just do this:
    foreach($x in (1.. 10)) {write-output $x*2} | out-file test.txt

    foreach has an equivalent in most languages, so it would seem more comfortable for developers in general.

  3. Hi Brain2000,

    Of course you could do that. This post is about the differences between foreach and foreach-object. Which one to use is up to you.

  4. foreach($x in (1.. 10)) {write-output $x*2} | out-file test.txt
    This command will throw the following error:
    An empty pipe element is not allowed.
    At line:1 char:46
    + foreach($x in (1.. 10)) {write-output $x*2} | <<<< out-file test.txt
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordEx
    ception
    + FullyQualifiedErrorId : EmptyPipeElement
    ———————
    Use following command to get the output:
    foreach($x in (1.. 10)) {write-output $x*2 | out-file test.txt}

  5. Very bright article.
    foreach is an alias of foreach-object, not likely to be any differences in how they work or how fast they are, its more likely that the way they are used

    try running “get-alias foreach” or you can try using “set-alias -name numbnuts -value foreach-object”

    Thanks anyway!

  6. @Traste: You are wrong and should apologize to Anita. That alias only applies when used in a pipeline operation.

    If you replace ForEach in this example with ForEach-Object or % you will get an error.

    ForEach ($file in Get-ChildItem) { Write-Host $file }

    These work however and are all the same:
    Get-ChildItem | ForEach-Object {Write-Host $_.Name}
    Get-ChildItem | ForEach {Write-Host $_.Name}
    Get-ChildItem | % {Write-Host $_.Name}

  7. Pingback: ForEach vs ForEach-Object in PowerShell « konab.com

  8. I notice a defect in the Foreach: example: the Foreach statememt sets $item for each object in $items, but the output statement refers to $elememt. It should read:

    Write-Host “Foreach: ”
    (Measure-Command { `
    Foreach ($item in $items) { `
    “Item: $item” `
    }}).totalmilliseconds

Comments are closed.