I have this strange observation:
I want to run an expression for as many times as there are files.
Yet, the following script always executes only once, no matter how many files are found by Get-ChildItem
:
(Get-ChildItem -Filter '*.png'), (Get-ChildItem -Filter '*.jpg') |
Sort-Object -Property 'Name' |
ForEach-Object -Begin { $idx = 0 } -Process { ++$idx; $idx; }
If I replace the expression with $_
, all rows are returned as expected:
(Get-ChildItem -Filter '*.png'), (Get-ChildItem -Filter '*.jpg') |
Sort-Object -Property 'Name' |
ForEach-Object -Begin { $idx = 0 } -Process { $_; }
>Solution :
As Mathias points out, (...), (...)
creates a nested array, which is not your intent (the ,
operator constructs an array from its operands, even if those operands are themselves arrays).
The best way to provide output from multiple commands as pipeline input is to use &
(or .
, if you need the commands to run directly in the caller’s scope) with a script block ({ ... }
), in which, as usual you can separate commands with ;
:
& { Get-ChildItem -Filter *.png; Get-ChildItem -Filter *.jpg } |
Sort-Object -Property Name |
ForEach-Object -Begin { $idx = 0 } -Process { ++$idx; $idx; }
This approach streams the command output, whereas use of $(...)
or @(...)
(which in this particular case can be used interchangeably) – $(Get-ChildItem -Filter *.png; Get-ChildItem -Filter *.jpg)
or @(Get-ChildItem -Filter *.png; Get-ChildItem -Filter *.jpg)
– collect all output first and then send it to the pipeline.
An simplified version of your command that makes do with a single Get-ChildItem
call, using the -Path
parameter’s support for multiple wildcard patterns:
Get-ChildItem -Path *.png, *.jpg |
Sort-Object -Property Name |
ForEach-Object -Begin { $idx = 0 } -Process { (++$idx) }
-
-Filter
is usually preferable, because it filters at the source, but it only supports one wildcard pattern at a time; while-Path
, which makes PowerShell filter the results is noticeably slower, the overhead from an extraGet-ChildItem
call may negate that advantage.- There’s also
-Include
/-Exclude
, which also filter on the PowerShell side, but, unfortunately, they do not work as one would intuitively expect: see this answer.
- There’s also
-
Also note the use of
(...)
around++$idx
, which causes the updated value to also be output.