PowerShell ForEach $file in $Files
This is a classic issue that has been fixed in PowerShell V3 IIRC. PowerShell's foreach
loop will allow you to iterate over a scalar value e.g.:
foreach ($i in 1) {$i}
That is handy because many times the collection you iterate can contain 0, 1 or N items e.g.:
$files = Get-ChildItem c:\temp\*.txtforeach ($file in $files) {$file}
In this case, Get-ChildItem
could return 0, 1 or N files. N files is great, we can iterate over that. However if it returned 1 file and then you had to stick that one file in an array so that you could use foreach
- well that would kind of suck. So foreach
allows you to iterate over a scalar object. The problem occurs when Get-ChildItem
returns 0 objects. In that case, an empty array is not assigned to $files. Instead $null is assigned. PowerShell considers $null a scalar and hence the foreach
loop will execute once where the iterated value is $null. That kind of sucks. And I and many other folks told the team this early on, so in V3 they changed foreach
to not iterate a scalar if the value is $null.
Another way to work around this in V1/V2 is to ensure the empty case generates an empty array instead of $null. You can do that using an @()
array expression e.g.
$files = @(Get-ChildItem c:\temp\*.txt)foreach ($file in $files) {$file}
This will work for 0, 1, and N files. It's works for 0 files because the @()
will result in an empty array being assigned to $files. foreach
will not execute its body when looping over an empty array.