I have a PowerShell script that gets a file listing and moves the files that meet a specific criteria. Why does the foreach
loop run even if the object is empty?
I would assume if $i did not exist it would not run. But if there are no results in $filePath why does the forEach loop run once? I have worked around my issue, but I am curious and I tried searching, but I could not find the answer.
To get this to work I just check to make sure $filePath exists before the forEach loop.
For example, if ($filePath){...
$filePath = Get-ChildItem -Path $sourceDir | Where-Object {! $_.PSIsContainer -AND ($_.Name -Match "^XXX_XXX*" -OR $_.Name -Match "^YYY_XX*")} ForEach($i in $filePath){ $sfName = $i.Name $sfDir = $i.Directory $tFileName = testFile $destDir $sfName $sFile = $sourceDir + $sfName $tFile = $destDir + $tFileName moveFile $sFile $tFile
Using break in loopsWhen a break statement appears in a loop, such as a foreach , for , do , or while loop, PowerShell immediately exits the loop. A break statement can include a label that lets you exit embedded loops. A label can specify any loop keyword, such as foreach , for , or while , in a script.
Like the Windows command line, Windows PowerShell can use the dir command to list files in the current directory. PowerShell can also use the ls and gci commands to list files in a different format.
If you have a text file with data you wish to use, you can use PowerShell Get-Content to list the contents of the file. Then use the PowerShell ForEach loop to iterate through the file line by line.
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\*.txt foreach ($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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With