What is actually safe to delete?
Space analysers show you where the bytes are. Cleanup scripts just delete. This one tells you what’s safe to remove and what it costs you, including which part of the Windows Installer cache to leave alone.
Reports by default. It deletes only when you pass -Apply, and it logs every file it removes. Nothing is uploaded.1Run the report
From an elevated PowerShell prompt. Add -Gui for a window, or -Quick to skip the slow checks.
powershell -ExecutionPolicy RemoteSigned -File .\safe-to-delete.ps1 Not Bypass, on purpose. This script is signed, and
RemoteSigned is what makes Windows actually check that. The first run asks whether
you trust Vitko Software, LLC - that prompt is the signature doing its job, and
answering Always run remembers it. Bypass would skip the check entirely,
which rather defeats the point of signing it.
Verify it yourself before you run anything:
Get-AuthenticodeSignature .\safe-to-delete.ps1 | Format-List Status, SignerCertificate Status should read Valid, and SignerCertificate should
name Vitko Software, LLC. Edit the file and it reads HashMismatch; append
anything below the signature block and it reads NotSigned. Either way that’s the
check working rather than a bad download - and it means any copy you find elsewhere that has
been altered will say so.
SHA-256, 116,222 bytes:
85DE730E076EC1D1DB34C5F564807CE7808625048EB93F8834143813B9534480
Get-FileHash .\safe-to-delete.ps1 -Algorithm SHA256 Same number on GitHub and here, because it's the same file. Worth knowing which check is which, though: this hash proves the download arrived intact, and nothing more - anyone able to change the file could change this number too. The Authenticode signature above is the one that can't be forged from a web server, so if you only run one check, run that one.
See what the code says, before you run it
This is the script's own help header, taken straight out of the file above when this page was built. It documents every switch, including the ones that delete. The file is Authenticode-signed, so the signature block sits at the end.
<#
.SYNOPSIS
Report what is eating a Windows system drive, and how confident you can be about reclaiming
each part of it. REPORTS BY DEFAULT - it deletes only when you pass -Apply.
.DESCRIPTION
Space analysers (WizTree, TreeSize) tell you WHERE the bytes are, and they are excellent at it.
Cleanup scripts DELETE things, and there are a dozen good ones on GitHub. Neither answers the
question in between, which is the one that actually stops people:
"Which of this is safe to remove, and what does removing it cost me?"
Worked example from the machine this was written on. The Windows Installer cache is 6.5 GB. Of
that, 403 MB is genuinely orphaned; deleting the other 6 GB breaks repair and uninstall for 143
installed products, and the user finds out weeks later with "the feature you are trying to use
is on a network resource that is unavailable". A size report cannot tell those apart. A cleanup
script that empties the folder is actively dangerous. Only a tool that checks each file against
the installer database can say which 403 MB is which.
So every finding carries a CONFIDENCE and a stated COST:
safe - regenerated on demand, or already dead. Removing it loses nothing.
caution - reclaimable, but you give something up, and the something is named.
leave - in use. Listed so you know why the space is not available to you.
WHY A SIGNED SCRIPT AND NOT AN EXE. The best-known tool for the installer-cache half of this is
an unsigned binary from around 2012. You are being asked to let an unsigned executable delete
files from C:\Windows\Installer on faith. A signed script is strictly more auditable: you can
read exactly what it is about to do before you run it. Nothing here needs compiled code.
WHY NOT JUST cleanmgr /sagerun. The built-in needs a registry preset configured per machine
before it will run unattended, emits nothing you can parse, and its target list is not
inspectable - you cannot read it and know what it is about to delete. This is a readable script
that names every target, its size, and what removing it costs you, before anything is removed.
INVARIANTS. These are boundaries, not preferences, and they hold whatever switches you pass:
* USER DATA IS NEVER TOUCHED. Not Downloads, Documents, Desktop, Pictures, or anything
OneDrive-backed. Deleting a user's Downloads folder is the single most hated behaviour in
the consumer-cleanup category and this tool does not have that code path at all. The only
user-profile paths it will ever remove from are AppData\Local\Temp and application caches
that the application rebuilds on next launch.
* NOTHING IS DELETED WITHOUT -Apply. The default run reports.
* IT REFUSES TO RUN DURING AN INSTALL. See -IgnoreActiveInstalls; a cleanup that races a
patch cycle is how you manufacture a support ticket.
* NOTHING IS UPLOADED. The JSON is written to your disk and read in your browser.
* IT NEVER REBOOTS ANYTHING. If the component store needs a restart to finish, it says so and
exits 3010 for your RMM to act on.
.PARAMETER OutFile
Where to write the JSON snapshot. Defaults to disk-reclaim.json on your Desktop.
.PARAMETER Gui
Show a results window instead of console output. Still read-only.
.PARAMETER Quick
Skip the slow checks (per-profile sizing, component-store analysis). Seconds instead of minutes.
.PARAMETER StaleProfileDays
A local profile unused for this many days is reported. Default 90.
.PARAMETER Category
Only run these categories: temp, updates, caches, installer, dumps, images, profiles, system.
Default is all of them.
.EXAMPLE
powershell -ExecutionPolicy RemoteSigned -File safe-to-delete.ps1
.EXAMPLE
powershell -ExecutionPolicy RemoteSigned -File safe-to-delete.ps1 -Gui
.EXAMPLE
powershell -ExecutionPolicy RemoteSigned -File safe-to-delete.ps1 -Quick -Category temp,updates
#> That's the first 72 lines of 1,848. Read the rest on GitHub, or open the raw file - it's the same bytes you'd download.
2Drop the file it wrote
The tool was called Disk Reclaim until recently, so the file it writes is still named
disk-reclaim.json. Same file, same place, on your Desktop.
| Location | Size | Confidence | Cost if you remove it |
|---|
Checked and found nothing
The case this exists for
On the machine this was written on the Windows Installer cache is 6.5 GB. A size report stops there. But 403 MB of it is genuinely orphaned - packages belonging to software that’s no longer installed - and the other 6 GB is referenced by 143 products that are still there. Delete that 6 GB and repair, modify and uninstall break for all 143. Nothing goes wrong that day. It goes wrong at the next patch or removal, with "the feature you are trying to use is on a network resource that is unavailable".
You can’t tell those apart by size. You have to check every cached file against the installer database and the registry, and only call it orphaned when both agree. That’s what this does, and it’s why its number is smaller than what a folder-size tool shows you.
Three pieces of cleanup advice that are wrong
All three come up near the top when you search for how to free space on Windows. The report tells you to skip all three, and why.
"Empty C:\Windows\Installer"
This is the big one. That folder holds the cached MSI and MSP files Windows Installer needs to repair, modify, patch and uninstall the software already on the machine. Delete a cached package for something that’s still installed and the machine keeps working fine until the next update or removal, which then fails with "the feature you are trying to use is on a network resource that is unavailable" and asks for an installer nobody kept. There are orphaned files in there and they’re real free space, but you need the installer database to find them.
"Clear the Prefetch folder"
Prefetch is usually a few dozen megabytes, and Windows rebuilds it by watching the next several boots and app launches. You give up some speed for an amount of space that won’t move your free figure at all. The report still measures it and shows you the number, because "we looked and it’s not worth it" beats leaving it off the list.
"Run DISM /StartComponentCleanup /ResetBase"
The plain cleanup is fine, and the report suggests it. It’s /ResetBase you want to
think about. It throws away the superseded components that let you uninstall an update, so after
it runs you can’t roll back anything on that machine. On one workstation, fine, that’s a call you
can make. Put it in a fleet-wide scheduled task and you’ve given up rollback everywhere, right
before the month you need it.
What it looks at
Component store, Windows Installer cache split into orphaned and in-use, the page file and hibernation file with their real sizes rather than what a file check reports, Delivery Optimization in both of its locations, Windows Update download cache, Panther and CBS setup logs, the kernel memory dump and minidumps, volume shadow copy storage, Windows.old and upgrade staging folders, per-user temp and browser caches, the recycle bin, and profiles nobody has signed into for however many days you set. Each one gets a size, a grade, and a sentence saying what it costs you to remove it.
Questions
Why not just run a cleanup script?
Because the decisions worth making aren’t safe by default. Take the Windows Installer cache: most of it’s still doing a job, and deleting the wrong part breaks repair and uninstall for software that’s still installed. A script that just empties the folder frees space today and hands you a support ticket later. This tells you which part is orphaned and which part has to stay.
Does it delete anything?
Not unless you pass -Apply. A plain run reads, reports, and writes one JSON file, and that’s the default. -Apply removes the SAFE rows only; the ones with a stated cost need -IncludeCaution on top, and the ones marked in-use can’t be removed at all. It refuses to run while an install or a patch cycle is in progress, and it never touches Documents, Desktop, Downloads or anything OneDrive is syncing.
If I do let it delete, what’s the record?
A plain-text log next to the JSON, one line per file with the full path and its size, plus a line for every file it couldn’t remove and why. It appends, so each run adds to the history rather than erasing the last one. Six weeks later, when someone asks what happened to a file, that log is the answer and you read it in Notepad. Turn it off with -NoRemovalLog.
Why a script instead of an executable?
Because you can read it before you run it. The best-known tool for the installer-cache half of this is an unsigned binary, and you’re asked to let it delete files out of C:\Windows\Installer on faith. Nothing here needs compiled code. It’s also Authenticode-signed and timestamped, so you can check who published it with Get-AuthenticodeSignature and Windows will check it for you under RemoteSigned - the timestamp means the signature keeps validating after the certificate expires.
Is anything uploaded?
No. The JSON stays on your disk and this page reads it in your browser.
Does it need administrator rights?
Yes, for the full picture. Only an administrator can read the servicing store, shadow copy storage and the installer database. It still runs without, and says on the report that the numbers are low.
What does it check that other tools miss?
Delivery Optimization, which lives in two separate places. Panther setup logs. The kernel memory dump. Volume shadow copies. The page file, which has an ACL that defeats a plain file check, so plenty of tools report it as absent. And the orphaned part of the installer cache. It also tells you to skip two popular ones: clearing Prefetch buys you nothing and slows boot, and a WinSxS cleanup with /ResetBase can’t be undone.
Open source
SafeToDelete is MIT-licensed at github.com/deadarcher/safe-to-delete. It's the same signed file this page serves, so you can read every rule before you run it, which is the point: a script that deletes things on your system drive shouldn't be a black box.
Think a row is graded wrong, or know a location it misses? Open an issue - disagreements about what's safe are exactly the feedback this wants.