Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mtboren/4f174c2d47ad4512168cace9f459d082 to your computer and use it in GitHub Desktop.
Save mtboren/4f174c2d47ad4512168cace9f459d082 to your computer and use it in GitHub Desktop.
Example of pipeline difference between ForEach-Object cmdlet and foreach() statement in PowerShell
<#
While we can iterate over objects with both ForEach-Object and the foreach() statement, only ForEach-Object emits objects
to the pipeline. The foreach() statement does _not_, which prevents us from doing any further cool things with objects
that might be created in the foreach() statement's scriptblock
Some examples:
#>
## no objects returned to pipeline, so we are done with the interesting things immediately
PS C:\> foreach ($intI in 1..10) {New-Object -Type PSObject -Property @{SomeCoolProperty = $intI}} | Measure-Object -Sum -Property SomeCoolProperty
At line:1 char:92
+ … bject -Type PSObject -Property @{SomeCoolProperty = $intI}} | Measure …
+ ~
An empty pipe element is not allowed.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : EmptyPipeElement
## but, ForEach-Object puts our juicy objects on the pipeline so we can continue our interesting interactions with said objects
PS C:\> 1..10 | ForEach-Object {New-Object -Type PSObject -Property @{SomeCoolProperty = $_}} | Measure-Object -Sum -Property SomeCoolProperty
Count : 10
Average :
Sum : 55
Maximum :
Minimum :
StandardDeviation :
Property : SomeCoolProperty
## less natural / slightly more cumbersome, but we could, of course, create a new variable to hold the resultant objects,
# and in a subsequent command, do something with the objects
PS C:\> $arrTmp = foreach ($intI in 1..10) {New-Object -Type PSObject -Property @{SomeCoolProperty = $intI}}
PS C:\> $arrTmp | Measure-Object -Sum -Property SomeCoolProperty
Count : 10
Average :
Sum : 55
Maximum :
Minimum :
StandardDeviation :
Property : SomeCoolProperty
## and, we could use a subexpression "$(foreach(...) {...})" to eventually get objects on the pipeline, but that defeats the
# whole power of the pipeline principle in PowerShell :frownie_face:
## Example of using the power of the pipeline (and being done after just the first object)
## ~0.5 seconds when getting just the first object :thumbs_way_up:
PS C:\> Measure-Command {1..1000 | ForEach-Object {Start-Sleep -Seconds 0.5; $_} | Select-Object -First 1}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 506
Ticks : 5061489
TotalDays : 5.85820486111111E-06
TotalHours : 0.000140596916666667
TotalMinutes : 0.008435815
TotalSeconds : 0.5061489
TotalMilliseconds : 506.1489
## Example of defeating one of the main purposes of the pipeline, causing _all_ objects to be considered before continuing
# on down the pipeline (the whole subexpression "$(...)" has to complete before any objects are then emitted down the pipeline)
## 8+ minutes to get just the first object! :thumbs_down:
PS C:\> Measure-Command {$(foreach ($intI in 1..1000) {Start-Sleep -Seconds 0.5; $intI}) | Select-Object -First 1}
Days : 0
Hours : 0
Minutes : 8
Seconds : 20
Milliseconds : 92
Ticks : 5000923992
TotalDays : 0.00578810647222222
TotalHours : 0.138914555333333
TotalMinutes : 8.33487332
TotalSeconds : 500.0923992
TotalMilliseconds : 500092.3992
## and, as you see, these varied times are specific to further object consumption down the pipeline (the way that we get exactly what we want in PS)
# The overall run duration to get all 1000 objects in either of these ways is the same, but part of the point is that we do not
# always need all 1000 objects
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment