I'm a novice in PowerShell.
Recently I encountered a problem about how to cascade commands or functions. I've found 2 ways:
CMD_B (CMD_A ($x))
$x | CMD_A | CMD_B
But, what's the difference between the above 2 ways?
For example, the results of Write-Output (Get-Process)
and Get-Process | Write-Output
look the same. Are there different details hidden?
I've searched the doc about grouping-operator ()
and Pipeline operator |
, and find:
When used as the first segment of a pipeline, wrapping a command or expression in parentheses invariably causes enumeration of the expression result. If the parentheses wrap a command, it's run to completion with all output collected in memory before the results are sent through the pipeline.
Grouping an expression before piping also ensures that subsequent object-by-object processing can't interfere with the enumeration the command uses to produce its output.
But I don't quite understand it. Maybe it's because I lack the basic knowledge of pipelines.
Thanks in advance.
Start from the base that Write-Output (Get-Process)
is the same as storing the output from Get-Process
in a variable and passing it as argument to Write-Output
. When you use (...)
the expression must be evaluated first, before the subsequent command receives that output, this can mean for example higher memory consumption.
# can be considered the same as `Write-Output (Get-Process)`
$tmp = Get-Process
Write-Output $tmp
$tmp = $null
With the pipeline instead what you have is One-at-a-time processing, the subsequent command receives and processes one item at a time as soon as the preceding in pipeline starts outputting.
This comparison between (...)
and pipelines is very easy to see if you add a bit of delay between each object outputted:
function Test-ProcessingFunction {
param(
[Parameter(ValueFromPipeline)]
[int[]] $int
)
process {
foreach ($i in $int) {
"Processing $i"
}
}
}
$rangeDelayed = {
0..10 | ForEach-Object { Start-Sleep -Milliseconds 200; $_ }
}
# nothing happens until `$rangeDelayed` finishes
Test-ProcessingFunction (& $rangeDelayed)
# as soon as `$rangeDelayed` outputs, it gets processed
& $rangeDelayed | Test-ProcessingFunction