Prune-Backups.ps1: Prune Backup Files with PowerShell
Do you have a program that dumps daily backups into a folder which would eat up your disk? Do you want to automatically delete some of those files but keep backups of certain ages? This is just the case for which I wrote Prune-Backups.ps1
param (
[ string ] $ Path = ( Get-Location ) ,
[ int ] $ Hours = 0 ,
[ int ] $ Days = 0 ,
[ int ] $ Weeks = 0 ,
[ int ] $ Months = 0 ,
[ int ] $ Years = 0 ,
[ switch ] $ Summary = $ true,
[ switch ] $ WhatIf
)
$ now = Get-Date
$ hourlyDates = 0 ..- $ Hours | % { $ now.addHours ( $ _) }
$ dailyDates = 0 ..- $ Days | % { $ now.addDays ( $ _) }
$ weeklyDates = 0 ..- $ Weeks | % { $ now.addDays ( $ _* 7 ) }
$ monthlyDates = 0 ..- $ Months | % { $ now.addMonths ( $ _) }
$ yearlyDates = 0 ..- $ Years | % { $ now.addYears ( $ _) }
$ datesToKeep = @ ( ) + $ hourlyDates + $ dailyDates + $ monthlyDates + $ weeklyDates + $ yearlyDates | Sort - Unique
$ files = Get-ChildItem - Path $ Path - File
function Get-ClosestFile {
param (
[ datetime ] $ referenceDate,
[ array ] $ files
)
foreach ( $ file in $ files) {
$ diff = ( New-TimeSpan - Start $ file.LastWriteTime - End $ referenceDate) .Duration( )
if ( ! $ smallestDiff -or $ diff -lt $ smallestDiff) {
$ smallestDiff = $ diff
$ closestFile = $ file
}
}
return $ closestFile
}
$ filesToKeep = @ ( )
foreach ( $ date in $ datesToKeep) {
$ file = Get-ClosestFile - referenceDate $ date - files $ files
if ( $ file -ne $ null -and $ filesToKeep -notcontains $ file) {
$ filesToKeep += $ file
}
}
$ filesToKeep = $ filesToKeep | Sort LastWriteTime - Unique
$ lengthDeleted = 0
$ files | ? { $ _ -notin $ filesToKeep} | % {
$ lengthDeleted += $ _.Length
if ( $ WhatIf) {
Write-Output " WhatIf: Deleting file '$ ( $ _.FullName ) ' [$ ( $ _.LastWriteTime ) ]"
} else {
Write-Output " Deleting file '$ ( $ _.FullName ) ' [$ ( $ _.LastWriteTime ) ]"
Remove-Item $ _ - Force
}
}
Write-Output " Operation complete."
if ( $ summary) {
Write-Output " Retained files:"
$ filesToKeep | % { " [$ ( $ _.LastWriteTime ) ] $ ( $ _.FullName ) " }
$ deleted = [ math ] ::round( $ lengthDeleted/ 1 Mb , 3 )
$ remaining = [ math ] ::round( ( $ filesToKeep | Measure - Sum Length) .Sum/ 1 Mb , 3 )
$ percentDeleted = [ math ] ::round( $ deleted/ ( $ remaining+ $ deleted) , 3 ) * 100
Write-Output " Removed $ ( $ deleted) MiB ($ ( $ percentDeleted) %), kept $ ( $ remaining) MiB"
}
Letβs say you want to keep a backup from every day of the last week, as well as copies from 2, 3, and 4 weeks ago, 1, 2, and 3 months ago, 1 and 2 years ago. You can try it from the folder in question with the -WhatIf
flag:
./ Prune- Backups.ps1 - Days 7 - Weeks 4 - Months 3 - Years 2 - WhatIf
It will report back which files would be deleted, which would be kept, and how much space youβll save.
Now you can create a scheduled daily task, pointing to a specific path and removing the -WhatIf
flag:
Program/script : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Add arguments (optional) : -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:\Scripts\Prune-Backups.ps1 -Path "C:\ProgramData\Vendor\Backups\" -Days 7 -Weeks 4 -Months 3 -Years 2
Note: No matter what, the most recent item in the folder will be kept. The default behavior of the script, if called with no parameters, is to keep only the most recent file.
% show system-information
No rights reserved. View source here . Provided as-is, no warranty, etc.
Built 2025-07-01 16:43:45 UTC with Zola on GitHub Actions , hosted on GitHub Pages.
Fonts: This page uses Roboto Flex with headings set in Instrument Serif and code in Inconsolata.
% tree deal.digital
deal.digital/
ββblog/
β ββlibrechat/
β ββshorelock/
β ββsmart-seagate/
β ββwintricks/
ββtools/
β ββnetlibram/
β ββprune/
β ββpwgen/
β ββtpmiddle/
ββcontact/
ββhome/
ββlinks/
ββnow/
ββsample/
ββtodo/
ββuses/
% show :3
__,,,,_
_ __..-;''`--/'/ /.',-`-.
(`/' ` | \ \ \\ / / / / .-'/`,_
/'`\ \ | \ | \| // // / -.,/_,'-,
/<7' ; \ \ | ; ||/ /| | \/ |`-/,/-.,_,/')
/ _.-, `,-\,__| _-| / \ \/|_/ | '-/.;.\'
`-` f/ ; / __/ \__ `/ |__/ |
`-' | -| =|\_ \ |-' |
__/ /_..-' ` ),' //
fL ((__.-'((___..-'' \__.'