Script
Remove files older than N days
Delete files whose last write time is older than a threshold. Preview first.
Preview is the default. Pass -Apply to delete. Keep -WhatIf on the first real run.
A file that cannot be deleted (in use, read-only, or access denied) is skipped with a warning, and the run carries on. The last line says how many files were removed and how many failed. Add -Force to include read-only files.
.\remove-old-files.ps1 -Path .\logs -OlderThanDays 30 -Filter *.log
.\remove-old-files.ps1 -Path .\logs -OlderThanDays 30 -Filter *.log -Apply -WhatIf
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
-Path |
string | Yes | Folder to clean. |
-OlderThanDays |
int | Yes | Age in days. Files last written before this cutoff are candidates. |
-Filter |
string | No | Wildcard filter. Default *. |
-Recurse |
switch | No | Include subfolders. |
-Force |
switch | No | Also delete read-only files. |
-Apply |
switch | No | Actually delete. Omit for a preview. |
Source
<#
.SYNOPSIS
Delete files older than a given number of days.
.DESCRIPTION
Preview unless -Apply is passed. Use -WhatIf with -Apply.
.PARAMETER Path
Folder to clean.
.PARAMETER OlderThanDays
Files with LastWriteTime older than this many days are candidates.
.PARAMETER Filter
Wildcard. Default *.
.PARAMETER Recurse
Include subfolders.
.PARAMETER Force
Also delete read-only files.
.PARAMETER Apply
Perform deletes.
.EXAMPLE
.\remove-old-files.ps1 -Path .\logs -OlderThanDays 30 -Filter *.log
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)]
[string]$Path,
[Parameter(Mandatory)]
[ValidateRange(1, 36500)]
[int]$OlderThanDays,
[string]$Filter = '*',
[switch]$Recurse,
[switch]$Force,
[switch]$Apply
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
throw "Folder not found: $Path"
}
$cutoff = (Get-Date).AddDays(-1 * $OlderThanDays)
# On Windows PowerShell 5.1, -Filter also matches 8.3 short names, so '*.htm'
# finds 'page.html'. Check the real name too. Brackets in -Filter are literal,
# so escape them for -like.
$namePattern = $Filter -replace '([\[\]])', '`$1'
$candidates = @(
Get-ChildItem -LiteralPath $Path -File -Filter $Filter -Recurse:$Recurse -ErrorAction SilentlyContinue -ErrorVariable scanErrors |
Where-Object { $_.Name -like $namePattern -and $_.LastWriteTime -lt $cutoff }
)
if ($scanErrors.Count -gt 0) {
Write-Warning "$($scanErrors.Count) folder(s) skipped (access denied or unreadable)."
}
if (-not $Apply) {
Write-Warning "Preview only. $($candidates.Count) file(s) older than $OlderThanDays day(s). Pass -Apply to delete."
$candidates | Select-Object FullName, LastWriteTime, Length
return
}
$removed = 0
$failed = 0
foreach ($item in $candidates) {
if ($PSCmdlet.ShouldProcess($item.FullName, 'Remove-Item')) {
try {
Remove-Item -LiteralPath $item.FullName -Force:$Force
$removed++
} catch {
$failed++
Write-Warning "Could not delete $($item.FullName): $($_.Exception.Message)"
}
}
}
Write-Output ("Removed {0}, failed {1}." -f $removed, $failed)
Downloaded it? Windows blocks scripts from the internet until you unblock them: Unblock-File -Path .\remove-old-files.ps1. See Run a script.
Edit this page on GitHub Edit remove-old-files.ps1 Report a problem