Powershell find folders, delete files leaving latest 5

Viewed 1478

We use software called Revit, files are saved as such: filename.rvt

Each time a user edits a file, Revit takes it upon itself to save the old file in the format filename.xxxx.rvt (where xxx is a number).

Over time when files are edited hundreds of times, we have many unnecessary files on the file server.

I am writing a script to:

  • Locate and folders containing Revit backup files
  • Delete all but the most recently modified 5 revit backup files

I have tried two approaches below

$searchpath = "e:\"
# Find a unique list of directories that contains a revit backup file (*.*.rvt)
$a = Get-ChildItem -Path $searchpath -Include *.*.rvt -Recurse | Select-object Directory -expandproperty FullName | Get-Unique -AsString

# For each folder that contains a single revit backup file (*.*.rvt)...
# - Sort by modified time
# - Select all except first 5
$a | Get-ChildItem -Include *.*.rvt | Sort-Object LastWriteTime -descending | select-object -skip 5 -property Directory,Name,CreationTime,LastWriteTime | Out-GridView -Title "Old Backups" -PassThru

The issue with this approach is that it only "skips" the first 5 files in the entire search result, not 5 in each folder.

Then I went about it using a loop, and this gets nowhere:

$searchpath = "e:\"

# Find a unique list of directories that contains a revit backup file (*.*.rvt)
$a = Get-ChildItem -Path $searchpath -Include *.*.rvt -Recurse | Select Directory | Get-Unique -AsString 

# For each folder that contains a single revit backup file (*.*.rvt)...
# - Sort by modified time
# - Select all except first 5
$a | foreach {
 $b += Get-ChildItem -Path $_.Directory.FullName -Include *.*.rvt | Sort-Object LastWriteTime -descending | select-object -skip 5 -property Directory,Name,CreationTime,LastWriteTime
}

$b | Out-GridView -Title "Old Backups" -PassThru

Any thoughts on the correct approach and whats going wrong?

4 Answers

An alternative solution that doesn't require grouping first and instead processes each directory separately:

& { Get-Item $path; Get-ChildItem -Directory -Recurse $path } | # get all dirs.
  ForEach-Object {                            # for each dir.
    Get-ChildItem -File $_.FullName/*.*.rvt | # get backup files in dir.
      Sort-Object -Descending LastWriteTime | # sort by last-write time, newest first
        Select-Object -Skip 5 |               # skip the 5 newest
          Remove-Item -Force -WhatIf          # delete
  }

Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.

Related