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
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.
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.
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.
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.
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}
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!
@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}
@Doug: I notice foreach is an alias for foreach-object
Pingback: ForEach vs ForEach-Object in PowerShell « konab.com
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
Apart from performance, another difference between foreach loop and foreach-object, is ability support loop control break and continue. I have added some details about it at http://techibee.com/powershell/difference-between-foreach-loop-and-foreach-object-in-powershell/2164