Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Using Powershell v2.0 I want to delete any files older than X days:

$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;
}

However, when $backups is empty I get: Remove-Item : Cannot bind argument to parameter 'Path' because it is null.

I've tried:

  1. Protecting the foreach with if (!$backups)
  2. Protecting the Remove-Item with if (Test-Path $file -PathType Leaf)
  3. Protecting the Remove-Item with if ([IO.File]::Exists($file.FullName) -ne $true)

None of these seem to work, what if the recommended way of preventing a foreach loop from being entered if the list is empty?

share|improve this question
    
@Dan - Tried both ($backups > 0) and (@($backups).count -gt 0), but neither work as expected when there are no files. –  SteB Dec 13 '12 at 11:49
add comment

3 Answers

up vote 5 down vote accepted

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
}
share|improve this answer
    
I've used the first one (it's easier to understand), I couldn't get the second one to work (I was probably doing something wrong). –  SteB Dec 13 '12 at 14:18
    
@SteB You're correct, my example was poorly explained (it still is), but I've provided an edit including your example code. For a better explanation of the behavior, please see this post on Keith Hill's blog, he is not only a PowerShell expert, but also a far better writer than me. Keith is active on StackOverflow, I would encourage you (or anyone interested in PS) to check out his stuff. –  jscott Dec 13 '12 at 14:43
add comment

Use the following to evaluate if the array has any contents:

if($backups.count -gt 0) { echo "Array has contents" } else { echo "Array is empty" }

If the variable doesn't exist Powershell will simply evaluate it as false, so no need to check if it exists.

share|improve this answer
    
Adding if ($backups.count -gt 0) stops the loop executing even when there's 1 item in $backups. $backups.count even on it's own doesn't output anything. –  SteB Dec 13 '12 at 11:30
    
@SteB Ah, I guess count isn't implemented for whatever object type is holding the data. I scan read and presumed it was an array. –  Dan Dec 13 '12 at 11:33
    
$count = @($backups).count; almost works, but when there are no files if f($count -gt 0) is true! –  SteB Dec 13 '12 at 11:47
add comment

I've developed a solution by running the query twice, once to get the files and once to count the files by casting the get-ChilItem to return an array (casting $backups as an array after the fact doesn't seem to work).
At least it works as expected (performance shouldn't be as issue since there'll never be more than a dozen files), if anyone knows of a single-query solution, please post it.

$count = @(Get-ChildItem -Path $zipFilepath | 
                Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")}).count;

if ($count -gt 0)
{
    $backups = Get-ChildItem -Path $zipFilepath | 
                Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")};

    foreach ($file in $backups)
    {
        Remove-Item $file.FullName;
    }
}
share|improve this answer
1  
I've edited the post for efficiency as it was easier than explaining in the comments. Just revert it if you don't like it. –  Dan Dec 13 '12 at 12:05
    
@Dan - Doh, can't believe I didn't spot that, thanks. –  SteB Dec 13 '12 at 14:08
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.