ForEach and ForEach-Object Differences

After far too long of not doing it, I’ve started using the full version of PowerShell commands (i.e. no aliases) and their parameters. Along with this, I’m dropping use of the '| ’ pipeline character from my scripts. Here’s my problem.

I used to use ForEach in something like the format below as an example:

Import-Module ActiveDirectory
$users = Get-ADUser -Filter *
ForEach ($user in $users) {
[string] $name = $
[string] $message = “Hello $name”
Write-Host $message

If i want to migrate this to ForEach-Object without using pipeline symbol, i would think that i could do the following :

Import-Module ActiveDirectory
$users = Get-ADUser -Filter *
ForEach-Object -InputObject $users -process {
[string] $name = $
[string] $message = “Hello $name”
Write-Host $message

But when in the second one, the value of ‘$_’, it is the array itself

So question is, is it possible for me to use the foreach-object to replicate the first example, without the use of the pipeline symbol?



Why do you want to drop the use of the pipeline - you lose one of PowerShell’s greatest strengths

Hi Richard,

Sorry, I didn’t word that good. What i mean is that if i can, i find

ForEach ($user in $users) {


looks better than than

$users | ForEach-Object {


So if i don’t need to use the the ’ | ’ character i won’t.

Best practices are to use the full command name and properties, but I’m not certain how i’d do this with ForEach-Object other than use the ’ | ’ symbol, since -inputobject doesnt seem to work the way i thought it would.

Hi Tim,

I think there is a misunderstanding here.

The keyword foreach is not the same thing as the cmdlet Foreach-Object.

Example using the keyword:

$Users = Get-ADUser -Filter *
foreach($User in $Users)
   'Some code here'

Here foreach is a keyword, for more information about this, check Get-Help about_Foreach.
This method requires that all objects are stored in the $Users variable and if there are many it could be heavy on memory usage.

Here is an example using the Cmdlet Foreach-Object (which can also be referenced to by its two aliases foreach and %):

Get-ADUser -Filter * | Foreach-Object { 'Some code here' }

In this example, Get-ADUser will immediately send each user retrieved from AD to Foreach-Object that can start to process the objects as they are retrieved.
This is a leaner approach since only the objects currently being processed are stored in memory and we don’t have to wait for AD to return all objects before we start processing them.

For more information on the Cmdlet Foreach-Object, see Get-Help Foreach-Object.

Thanks Simon,

Ah, okay, thats starting to make sense. So if i understand right ForEach-Object would only ever normally be used when it is prefixed with an object that is piped to it, or if you wanted to pass an entire object in one via -inputobject?

I think the thing that’s really thrown me is that ForEach is listed as an alias for ForEach-Object in PowerShell.

PS C:\Windows\system32> Get-Alias -Name foreach

CommandType Name Source

Alias foreach -> ForEach-Object

So i thought it would be possible for me also to use the same format of command I’d used in ForEach. I was searching for the property of the ForEach-Object command to use that would allow me to do that.

ForEach-Object only works with pipeline input. Even if you could use it as the first or only command in a pipeline, it would be far slower than using the foreach keyword.

That said, I wouldn’t recommend going to either extreme (using only $users | ForEach-Object or only foreach ($user in $users)). These have different performance characteristics, with the keyword typically being faster but at the expense of requiring more memory. If you force yourself into never using the pipeline, you’re eventually going to run into OutOfMemoryExceptions when handling large sets of data.

thanks Dave,

I’ll work on the basis that if i know the size of the dataset and it’s reasonable, i’ll use foreach, otherwise foreach-object.

One more thing, with
foreach ($object in $collection) {}
but not with
$objects | ForEach-Object {}
you can use the continue keyword to jump to the next item in the collection like you can with the various looping constructs.