Temp folder cleanup is the kind of task everybody does by hand once, gets uncomfortable with, and then automates badly. The uncomfortable part is the three-week-old .part download sitting in someone's temp folder, or the log file that's still being written to — scripts that just do Remove-Item $env:TEMP\* don't care. They'll eat it.
Here's the cleanup script I actually run, and the three rules that make it safe enough to schedule.
Rule 1: never delete by age alone, always by last-touched age
The failure mode of naive cleanup isn't deleting too much — it's deleting something live. A file's creation date tells you nothing; a file being written to right now still has a creation date from three weeks ago if the folder was restored from backup.
What matters is last write time: if a file hasn't been touched in 3+ days, nothing has it open, nothing is appending to it, and nobody is actively using it. The script's -MinFileAgeDays parameter (default 3) filters everything through that check before a single file is considered:
$MinFileAge = (Get-Date).AddDays(-$MinFileAgeDays)
$targets | Where-Object { $_.LastWriteTime -lt $MinFileAge }
Raise it to 7 or 14 on busy servers. On a terminal server with users in session all day, that one number is the difference between a maintenance window and an incident.
Rule 2: -WhatIf has to mean something
PowerShell's SupportsShouldProcess attribute gives you -WhatIf and -Confirm for free, but only if you route every destructive call through ShouldProcess. The script does:
if ($PSCmdlet.ShouldProcess($file.FullName, "Remove (age $([math]::Round($age)) days)")) {
Remove-Item -LiteralPath $file.FullName -Force -ErrorAction SilentlyContinue
$freed += $file.Length
}
Run it once with -WhatIf and you get a complete preview — full paths, ages, counts — with zero deletions. It's a dry run you can paste into a change ticket as evidence of what would happen.
Rule 3: the script reports, it doesn't just delete
A cleanup that leaves no trace is a cleanup nobody can audit. Each run appends a line to %ProgramData%\OpsKit\disk-cleanup.csv:
Timestamp, Host, FreedMB
2026-10-08 03:14:02, WEB01, 812.4
Five weeks later, when someone asks why disk space jumped on Tuesday, the answer is one Import-Csv away. It also gives the script a natural heartbeat — an empty CSV section means the scheduled task stopped running, which you notice before the disk fills up.
What it actually cleans
-
User temp folders (
$env:LOCALAPPDATA\Temp) for every profile on the box — not just the currently logged-in one -
System temp (
$env:windir\Temp) -
Windows Update download cache (
$env:windir\SoftwareDistribution\Download) — usually the biggest single win after a patch cycle, and safe to clear when the update service isn't mid-install - Old logs in paths you configure, age-gated the same way
.\disk-cleanup.ps1 -WhatIf # preview, delete nothing
.\disk-cleanup.ps1 -MinFileAgeDays 7 # only files idle a week
.\disk-cleanup.ps1 -MinFileAgeDays 3 -KeepDays 30 # logs: age-gate 3, retention 30
Try it before you trust it
disk-cleanup.ps1 is one of two scripts I keep MIT-licensed and free in the powershell-admin-scripts repo — source visible, no account, no telemetry. The companion there is ssl-expiry-check.ps1, which catches expiring certificates before your users do.
The full kit — backup rotation, service watchdog, event-log alerting, inventory export, share and password audits, patch reporting, and the user-offboarding checklist — is $7 on Gumroad with a 30-day refund. If offboarding is the only thing you need, the standalone script is $2.
Related: How to get an email when a Windows scheduled task fails - the watchdog I run over exactly these kinds of jobs (TaskWatch, free mini sample).
Top comments (0)