Protect foreach loop when empty list
Solution 1:
With Powershell 3 the foreach
statement does not iterate over $null
and the issue described by OP no longer occurs.
From the Windows PowerShell Blog post New V3 Language Features:
ForEach statement does not iterate over $null
In PowerShell V2.0, people were often surprised by:
PS> foreach ($i in $null) { 'got here' }
got here
This situation often comes up when a cmdlet doesn’t return any objects. In PowerShell V3.0, you don’t need to add an if statement to avoid iterating over $null. We take care of that for you.
For PowerShell $PSVersionTable.PSVersion.Major -le 2
see the following for original answer.
You have two options, I mostly use the second.
Check $backups
for not $null
. A simple If
around the loop can check for not $null
if ( $backups -ne $null ) {
foreach ($file in $backups) {
Remove-Item $file.FullName;
}
}
Or
Initialize $backups
as a null array. This avoids the ambiguity of the "iterate empty array" issue you asked about in your last question.
$backups = @()
# $backups is now a null value array
foreach ( $file in $backups ) {
# this is not reached.
Remove-Item $file.FullName
}
Sorry, I neglected to provide an example integrating your code. Note the Get-ChildItem
cmdlet wrapped in the array. This would also work with functions which could return a $null
.
$backups = @(
Get-ChildItem -Path $Backuppath |
Where-Object { ($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like "backup*") }
)
foreach ($file in $backups) {
Remove-Item $file.FullName
}
Solution 2:
I know this is an old post but I'd like to point out that the ForEach-Objec
cmdlet doesn't suffer the same issue as using the ForEach
key word. So you can pipe the results of DIR
to ForEach
and just reference the file using $_, like:
$backups | ForEach{ Remove-Item $_ }
You can actually forward the Dir command itself through the pipe and avoid even assigning the variable like:
Get-ChildItem -Path $Backuppath |
Where-Object {
($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and `
(-not $_.PSIsContainer) -and ($_.Name -like "backup*")
} |
ForEach{ Remove-Item $_ }
I added line breaks for readability.
I understand some people like ForEach/In for readability. Sometimes ForEach-Object
can get a little hairy, especially if you are nesting as it gets hard to follow the $_
reference. At any rate, for a small operation like this it's perfect. Many people also assert it's faster however I've found that to be only slightly.