header1   header
header
header Register : : Login header
header
connector   connector
menuleft menuright
submenu   submenu
left
Deleting old file and folders with remove-item -recurse option
Last Post 27 Aug 2010 10:04 AM by 0ptikGhost. 19 Replies.
Printer Friendly
  •  
  •  
  •  
  •  
  •  
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages Resolved
BikeBoyUser is Offline
New Member
New Member
Posts:25
Avatar

--
22 Jul 2010 07:30 AM
    I have the following script to delete the old files/folders on a share. I need to keep files that were created earlier than 30 days.$LastWrite seems to look at Date Created, and not Date Modified.

    Problem is whenever there are folders that where created 30 days ago, script deletes them, even though there may be new folders/files inside those old folders

    Function RemoveOldFile
    {
    $TargetFolder = \\MyUNCpath "

    $days = 30 if (Test-Path $TargetFolder)
    { $Now = Get-Date
    $LastWrite = $Now.AddDays(-$days) Get-ChildItem $Targetfolder |Where {$_.LastWriteTime -le "$LastWrite"}|remove-item -recurse }
     Else
    {Write-Host "The Folder $TargetFolder Does Not Exist!"}
    } RemoveOldFile
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    22 Jul 2010 08:29 AM

    Is this what you need?

    function Remove-Items
    {
        $targetFolder = "\\MyUNCpath"

        if (Test-Path -Path $targetFolder)
        {
            $thirtyDaysAgo = (Get-Date).AddDays(-30)       
            Get-ChildItem -Path $targetfolder -Recurse | Where-Object { $_.CreationTime -lt $thirtyDaysAgo } | Remove-Item
        }
        else
        {
            Write-Host "$targetFolder does not exist."
        }
    }

    Remove-Items

    That basically removes any item that is a child of the supplied path that is older that 30 days.

    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    22 Jul 2010 11:09 AM
    That's good, and thanks for your response. i added -recurse to Remove-Item ...but the problem still is that if there's an old folder, it gets deleted even though it has new files in it.

    So when the script sees Folder older than 30 days it wacks it, even though within it may be files or folders that are new
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    23 Jul 2010 05:57 AM

    What about this?

    function Remove-Items
    {
        $targetFolder = "\\MyUNCpath"

        if (Test-Path -Path $targetFolder)
        {
            $thirtyDaysAgo = (Get-Date).AddDays(-30)       
            Get-ChildItem -Path $targetfolder | Where-Object { $_.CreationTime -lt $thirtyDaysAgo } | ForEach-Object {
                if ($_.PSIsContainer)
                {
                    if ((Get-ChildItem -Path $_.FullName -Recurse | Where-Object { $_.CreationTime -gt $thirtyDaysAgo }).Count -gt 0)
                    {
                        return
                    }
                    else
                    {
                        return $_
                    }
                }
                else
                {
                    if ($_.CreationTime -lt $thirtyDaysAgo)
                    {
                        return $_
                    }
                    else
                    {
                        return
                    }
                }
            } | Remove-Item -Recurse
        }
        else
        {
            Write-Host "$targetFolder does not exist."
        }
    }

    Remove-Items

    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    23 Jul 2010 10:27 AM
    • Accepted Answer
    That one just skips all the folders and files, did not delete anything
    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    23 Jul 2010 10:55 AM
    actually it worked when I added another -Recurse here:

    but still deleted a whole folder when I had a new file in the old folder. my goal is to leave a file if it's new, and just delete a folder.

    if (Test-Path -Path $targetFolder)
    {
    $thirtyDaysAgo = (Get-Date).AddDays(-30)
    Get-ChildItem -Path $targetfolder -Recurse | Where-Object { $_.CreationTime -lt $thirtyDaysAgo } | ForEach-Object {
    if ($_.PSIsContainer)
    {
    if ((Get-ChildItem -Path $_.FullName -Recurse | Where-Object { $_.CreationTime -gt $thirtyDaysAgo }).Count -gt 0)
    {
    return
    }
    else
    {
    return $_
    }
    }
    else
    {
    if ($_.CreationTime -lt $thirtyDaysAgo)
    {
    return $_
    }
    else
    {
    return
    }
    }
    } | Remove-Item -Recurse
    }
    }

    Remove-Items
    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    23 Jul 2010 11:02 AM
    GWHowarth88, I think this is going to work out for me. I see what you did with the ForEach-Object function, so I can work with it. Thank you very much, this is a good way to learn PS
    George HowarthUser is Offline
    Basic Member
    Basic Member
    Posts:360
    Avatar

    --
    26 Jul 2010 01:39 AM
    I think what you are describing isn't going to be easy to accomplish because you have to go along "tagging" directories you don't want to be deleted. Good luck with it.
    0ptikGhostUser is Offline
    Basic Member
    Basic Member
    Posts:296
    Avatar

    --
    26 Jul 2010 02:34 PM

    Try this:

    $TargetFolder = '\\MyUNCpath' # remove old files $OldFileTime = (Get-Date).AddDays(-30) Get-ChildItem -Path $TargetFolder -Recurse | Where-Object -FilterScript { -not $_.PSIsContainer } | Where-Object -FilterScript { $_.LastWriteTime -le $OldFileTime } | Remove-Item -Force # now remove all empty directories Get-ChildItem -Path $TargetFolder -Recurse | Where-Object -FilterScript { $_.PSIsContainer } | Sort-Object -Descending | Where-Object -FilterScript { -not $($_.GetFiles() + $_.GetDirectories()) } | Remove-Item

    Please do note that it will delete all empty directories!

    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    29 Jul 2010 08:27 AM
    0ptikGhost,
    That will work too. Actually I need to log the files that I am deleting, and I found that the best loging is as follows:

    # Create log file
    [string]$logFile = "\\MyUNCpath"
    "Deleting files on $targetFolder at $CurDate" | Out-File -filepath $logFile -encoding oem

    my code | Out-File -filepath $logFile -encoding oem -append


    But the question is how to first log and then pipe it to Remove-Item -Force ? The way I have it now is it only ogs but does not delete, here's the script:


    $TargetFolder = '\\MyUNC
    $CurDate = get-date

    # Create log file
    [string]$logFile = "D:\DeleteLog.txt"
    "Deleting files on $targetFolder at $CurDate" | Out-File -filepath $logFile -encoding oem


    # remove old files
    $OldFileTime = (Get-Date).AddDays(-30)
    Get-ChildItem -Path $TargetFolder -Recurse |
    Where-Object -FilterScript { -not $_.PSIsContainer } |
    Where-Object -FilterScript { $_.LastWriteTime -le $OldFileTime } | Out-File -filepath $logFile -encoding oem -append | Remove-Item -Force

    #Out-File -filepath $logFile -encoding oem -append

    # now remove all empty directories
    Get-ChildItem -Path $TargetFolder -Recurse |
    Where-Object -FilterScript { $_.PSIsContainer } |
    Sort-Object -Descending |
    Where-Object -FilterScript { -not $($_.GetFiles() + $_.GetDirectories()) } |
    Remove-Item
    ## end script

    I tried something like:
    Where-Object -FilterScript { $_.LastWriteTime -le $OldFileTime } | Out-File -filepath $logFile -encoding oem -append; Remove-Item -Force
    but got an output:

    cmdlet Remove-Item at command pipeline position 1 Supply values for the following parameters: Path[0]: 0
    0ptikGhostUser is Offline
    Basic Member
    Basic Member
    Posts:296
    Avatar

    --
    01 Aug 2010 11:16 AM

    Use Foreach-Object to perform the desired action and then pass the item on to the next pipeline task.

    # remove old files $OldFileTime = (Get-Date).AddDays(-30) Get-ChildItem -Path $TargetFolder -Recurse | Where-Object -FilterScript { -not $_.PSIsContainer } | Where-Object -FilterScript { $_.LastWriteTime -le $OldFileTime } | Foreach-Object -Process { $_ | Out-File -filepath $logFile -encoding oem -append ; $_ } | Remove-Item -Force

    Be aware that you might need to perform some formatting depending on how you want the items to be logged. Another option might be to do the Remove-Item first and do the logging last.

    # remove old files $OldFileTime = (Get-Date).AddDays(-30) Get-ChildItem -Path $TargetFolder -Recurse | Where-Object -FilterScript { -not $_.PSIsContainer } | Where-Object -FilterScript { $_.LastWriteTime -le $OldFileTime } | Foreach-Object -Process { Remove-Item -Path $_.PSPath -Force ; $_ } | Out-File -filepath $logFile -encoding oem -append
    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    02 Aug 2010 11:54 AM
    works like a charm, I love Foreach-Object. The default formating is good, since it has the Mode ( file or folder), LastWriteTime Length, and Name .
    Thanks a bunch

    PS one quick question, is -Force param in Remove-Item -Force   needed in case the file is locked up by some other process?
    0ptikGhostUser is Offline
    Basic Member
    Basic Member
    Posts:296
    Avatar

    --
    03 Aug 2010 03:17 PM

    From Get-Help Remove-Item -Detailed:

        -Force []
            Allows the cmdlet to remove items that cannot otherwise be changed, such as hidden or read-only files or read-o
            nly aliases or variables. The cmdlet cannot remove constant aliases or variables.  Implementation varies from p
            rovider to provider. For more information, see about_Providers. Even using the Force parameter, the cmdlet cann
            ot override security restrictions.

    I include it to remove hidden or read-only files. I think you'll still get an error for other scenarios such as access denied.

    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    08 Aug 2010 09:52 PM
    OptikGhost, here's another thought:

    Say there's one folder called "Exception" contents of which I don't want to delete. Can I still keep the same structure of the script, and accomplish that? I do something like this, but the contents of "Exception" folder still get deleted, because the first part is based on deleteing files only:

    Where-Object -FilterScript { -not $_.PSIsContainer }

    The folder is left alone, because it's excluded in the second part of the script. I'd like to keep same logic, but not delete files in the exception folder :)


    # remove old files
    $OldFileTime = (Get-Date).AddDays(-30)
    Get-ChildItem -Path $TargetFolder -Exclude "Exception" -Recurse |
    Where-Object -FilterScript { -not $_.PSIsContainer } |
    Where-Object -FilterScript { $_.LastWriteTime -le $OldFileTime } |
    Foreach-Object -Process { $_ | Out-File -filepath $logFile -encoding oem -append ; $_ } |
    Remove-Item -Force
    #}

    # now remove all empty directories
    Get-ChildItem -Path $TargetFolder -Exclude "Exception" -Recurse |
    Where-Object -FilterScript { $_.PSIsContainer } |
    Sort-Object -Descending |
    Where-Object -FilterScript { -not $($_.GetFiles() + $_.GetDirectories()) } |
    Foreach-Object -Process { $_ | Out-File -filepath $logFile -encoding oem -append ; $_ } |
    Remove-Item
    0ptikGhostUser is Offline
    Basic Member
    Basic Member
    Posts:296
    Avatar

    --
    23 Aug 2010 07:03 PM

    Here's a very quick reply, I'll try to post a possible solution later tonight (sorry it's been so long since my last post... work's been kicking my rear!)

    The -Exclude parameter for Get-ChildItem only matches names (not paths) so any file whose name is not Exception will still match even if it resides inside an Exception folder.

    0ptikGhostUser is Offline
    Basic Member
    Basic Member
    Posts:296
    Avatar

    --
    23 Aug 2010 07:33 PM

    I think what you want to do is filter by FullName. Perhaps something like this:

    # remove old files $OldFileTime = (Get-Date).AddDays(-30) Get-ChildItem -Path $TargetFolder -Recurse | Where-Object -FilterScript { -not $_.PSIsContainer } | Where-Object -FilterScript { $_.FullName -match '*\Exception\*' } | Where-Object -FilterScript { $_.LastWriteTime -le $OldFileTime } | Foreach-Object -Process { $_ | Out-File -filepath $logFile -encoding oem -append ; $_ } | Remove-Item -Force #} # now remove all empty directories Get-ChildItem -Path $TargetFolder -Exclude Exception -Recurse | Where-Object -FilterScript { $_.PSIsContainer } | Sort-Object -Descending | Where-Object -FilterScript { -not $($_.GetFiles() + $_.GetDirectories()) } | Foreach-Object -Process { $_ | Out-File -filepath $logFile -encoding oem -append ; $_ } | Remove-Item
    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    26 Aug 2010 12:00 PM

    Thanks for your response,
    I got a bad arg error, does '*\Exception\*' need to be in double-quotes?

    PS C:\myscriptPath.ps
    Bad argument to operator '-match': parsing "*\Exception\*" - Quantifier {x,y} following nothing..
    At C:\myscriptPath.ps 1:28 char:48
    + Where-Object -FilterScript { $_.FullName -match <<<< '*\Exception\*' } |
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : BadOperatorArgument
    0ptikGhostUser is Offline
    Basic Member
    Basic Member
    Posts:296
    Avatar

    --
    26 Aug 2010 02:49 PM

    Oops! Nope, it does not need to be in double-quotes although using double-quotes won't hurt anything in this case. The problem is that the -match operator expects a regular expression and '*\Exception\*' is not a valid regular expression. It is a valid wildcard pattern so we should be able to use the -like operator:

    Where-Object -FilterScript { $_.FullName -like '*\Exception\*' }

    If you still want to use a regular expression then it should look like the following:

    Where-Object -FilterScript { $_.FullName -match '.*\\Exception\\.*' }
    BikeBoyUser is Offline
    New Member
    New Member
    Posts:25
    Avatar

    --
    27 Aug 2010 07:55 AM
    Thanks
    -nolike works, like Where-Object -FilterScript { $_.FullName -notlike '*\Exception\*' }

    BTW, do you know how to equate pipeline variable to null?? I want to check if $_. is null, and if it's not do something, like so:

    if ($_. -ne $null)
    {

    $_.Refresh();
    .... more code
    }


    I am getting an error:
    Unexpected token '.' in expression or statement. if ($_. <<<< -ne $null)

    so it doesn't like equating current object to null?
    0ptikGhostUser is Offline
    Basic Member
    Basic Member
    Posts:296
    Avatar

    --
    27 Aug 2010 10:04 AM

    Geez! Another uncharacteristic mistake on my part... That's what happens when I don't try out suggestions before making them. -notlike is the correct operator to use as you correctly point out.

    If you want to check the object in the pipeline against null then your condition is simply $_ -ne $null. Notice there is no period there after the $_. That's what the error is trying to tell you. Notice that the unexpected token is the period. The <<<< delimiter points to the character it was not expecting, in this case the period after the $_.

    You are not authorized to post a reply.


    Active Forums 4.3
    right
    footer   footer
    footer Sponsored by Quest Software • SAPIEN Technologies • Compellent • Microsoft Windows Server 2008 R2 footer
    footer   footer