Install
openclaw skills install win-cleanerDeep clean Windows C drive junk files. Analyzes disk usage, identifies safe-to-delete items, and cleans caches, temp files, logs, browser data, and application caches while protecting user data. Use when the user asks to clean C drive, free up disk space, or remove junk files on Windows.
openclaw skills install win-cleanerYou are a disk cleanup specialist. This skill uses a scan-first, pattern-match, clean-later strategy that adapts to any Windows computer.
Primary directive: Maximize freed space while guaranteeing zero user data loss and zero system stability impact.
Use this to prioritize if the user wants a quick clean vs. deep clean:
| Phase | Typical Yield | Time | Priority |
|---|---|---|---|
| 4a (Package managers) | 2-6 GB | 1-2 min | HIGH — always run |
| 4b (Windows junk) | 0.5-4 GB | 2-3 min | HIGH — always run |
| 4c (DISM) | 0.5-3 GB | 5-10 min | MEDIUM |
| 4d (VSS resize) | 0.5-2 GB | 1 min | MEDIUM |
| 5a (Pattern caches) | 0.5-3 GB | 2-5 min | HIGH — always run |
| 5b (Browser caches) | 0.3-2 GB | 1-2 min | HIGH — always run |
| 5c-e (IDE/Corrupted/GPU) | 0.1-2 GB | 1-3 min | MEDIUM |
| 6 (User decisions) | 2-10 GB | varies | Depends on user |
If user asks for "quick clean": Phases 1 → 4a → 4b → 5a → 5b → 7. Skip DISM and VSS. If user asks for "deep clean": All phases in order.
C:\Windows\System32, C:\Windows\SysWOW64, or C:\Windows\WinSxS (except via DISM which is safe)C:\Windows\System32\DriverStore (driver store).exe, .dll, .sys files anywhere on diskC:\Program Files or C:\Program Files (x86)format, cleanmgr /sageset, or any tool that opens a GUIrm -rf C:\ or del /f /s C:\*When using regex to find cache folders, apply these constraints:
-eq, -contains), never substring matching (-match, -like).git subfolder, package.json, Cargo.toml, or CMakeLists.txt file (indicates a project, not cache)Readme or README fileBefore any deletion, verify:
Get-Item $path | Select-Object LinkType)Run these 3 commands in parallel:
# 1a. Disk usage summary
Get-PSDrive C | ForEach-Object {
$total = [math]::Round(($_.Used + $_.Free)/1GB, 2)
$used = [math]::Round($_.Used/1GB, 2)
$free = [math]::Round($_.Free/1GB, 2)
$pct = [math]::Round($_.Used/($_.Used+$_.Free)*100, 1)
Write-Host "C: Total=${total}GB Used=${used}GB Free=${free}GB Usage=${pct}%"
# Store for final report comparison
Write-Host "PHASE1_USED=$used"
}
# 1b. Top-level directory sizes (excluding reparse points)
Get-ChildItem C:\ -Directory -ErrorAction SilentlyContinue -Attributes !ReparsePoint | ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
[PSCustomObject]@{Name=$_.Name; SizeGB=[math]::Round($size/1GB, 2)}
} | Sort-Object SizeGB -Descending | Format-Table -AutoSize
# 1c. User profile sizes
Get-ChildItem C:\Users -Directory -ErrorAction SilentlyContinue | ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
[PSCustomObject]@{User=$_.Name; SizeGB=[math]::Round($size/1GB, 2)}
} | Sort-Object SizeGB -Descending | Format-Table -AutoSize
Run these in parallel (2-3 PowerShell calls):
$locations = @(
[PSCustomObject]@{Name="Windows Temp"; Path="C:\Windows\Temp"},
[PSCustomObject]@{Name="User Temp"; Path=$env:TEMP},
[PSCustomObject]@{Name="Prefetch"; Path="C:\Windows\Prefetch"},
[PSCustomObject]@{Name="Update Downloads"; Path="C:\Windows\SoftwareDistribution\Download"},
[PSCustomObject]@{Name="Delivery Optimization"; Path="C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization"},
[PSCustomObject]@{Name="Error Reports"; Path="C:\ProgramData\Microsoft\Windows\WER"},
[PSCustomObject]@{Name="Panther Setup Logs"; Path="C:\Windows\Panther"},
[PSCustomObject]@{Name="CBS Logs"; Path="C:\Windows\Logs\CBS"},
[PSCustomObject]@{Name="DISM Logs"; Path="C:\Windows\Logs\DISM"},
[PSCustomObject]@{Name="Event Logs"; Path="C:\Windows\System32\winevt\Logs"},
[PSCustomObject]@{Name="Windows Installer"; Path="C:\Windows\Installer"},
[PSCustomObject]@{Name="ProgramData Pkg Cache"; Path="C:\ProgramData\Package Cache"},
[PSCustomObject]@{Name="Thumbnail Cache"; Path="$env:LOCALAPPDATA\Microsoft\Windows\Explorer"},
[PSCustomObject]@{Name="Font Cache"; Path="$env:LOCALAPPDATA\Microsoft\Windows\Fonts"}
)
foreach ($loc in $locations) {
if (Test-Path $loc.Path) {
$size = (Get-ChildItem $loc.Path -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($size -gt 1MB) {
[PSCustomObject]@{Location=$loc.Name; SizeMB=[math]::Round($size/1MB,1)}
}
}
} | Sort-Object SizeMB -Descending | Format-Table -AutoSize
# Hibernation file
if (Test-Path C:\hiberfil.sys) {
$h = Get-Item C:\hiberfil.sys -Force
Write-Host "hiberfil.sys: $([math]::Round($h.Length/1GB,2)) GB (disable with: powercfg /h off)"
}
# Page file
if (Test-Path C:\pagefile.sys) {
$p = Get-Item C:\pagefile.sys -Force
Write-Host "pagefile.sys: $([math]::Round($p.Length/1GB,2)) GB"
}
# Swap file
if (Test-Path C:\swapfile.sys) {
$s = Get-Item C:\swapfile.sys -Force
Write-Host "swapfile.sys: $([math]::Round($s.Length/1GB,2)) GB"
}
# Windows.old
if (Test-Path C:\Windows.old) {
$wo = (Get-ChildItem C:\Windows.old -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
Write-Host "Windows.old: $([math]::Round($wo/1GB,2)) GB (can be removed via Disk Cleanup → Clean up system files)"
}
# Memory dumps
Get-ChildItem C:\Windows\*.dmp -ErrorAction SilentlyContinue | ForEach-Object {
Write-Host "Crash dump: $($_.Name) = $([math]::Round($_.Length/1MB,1)) MB"
}
if (Test-Path C:\Windows\Memory.dmp) {
$md = Get-Item C:\Windows\Memory.dmp
Write-Host "Memory.dmp: $([math]::Round($md.Length/1GB,2)) GB"
}
# Live kernel dump
if (Test-Path C:\Windows\LiveKernelReports) {
$lk = (Get-ChildItem C:\Windows\LiveKernelReports -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($lk -gt 10MB) { Write-Host "LiveKernelReports: $([math]::Round($lk/1MB,1)) MB" }
}
# VSS / System Restore
vssadmin list shadowstorage 2>&1
# DISM component store analysis
dism /online /cleanup-image /analyzecomponentstore 2>&1 | Select-String -Pattern "recommend|Actual|claimed|cleanup" -SimpleMatch
# Find large non-system files at C:\ root
Get-ChildItem C:\ -File -ErrorAction SilentlyContinue | Where-Object {
$_.Length -gt 50MB -and
$_.Name -notin @('hiberfil.sys','pagefile.sys','swapfile.sys','DumpStack.log')
} | ForEach-Object {
Write-Host "C:\$($_.Name): $([math]::Round($_.Length/1MB,1)) MB — suspicious large file at root"
}
# Check non-standard root directories
@("C:\tmp", "C:\temp", "C:\backup", "C:\old", "C:\dump") | ForEach-Object {
if (Test-Path $_) {
$size = (Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($size -gt 10MB) {
Write-Host "$_ : $([math]::Round($size/1MB,1)) MB — non-standard root directory"
Get-ChildItem $_ -Recurse -File -ErrorAction SilentlyContinue | Sort-Object Length -Descending | Select-Object -First 5 | ForEach-Object {
Write-Host " $($_.Name): $([math]::Round($_.Length/1MB,1)) MB"
}
}
}
}
LocalLow ($env:USERPROFILE\AppData\LocalLow) is often overlooked but can hold GPU driver caches, game saves, and app configs. It must be scanned.
$appDataRoots = @{
$env:LOCALAPPDATA = "Local"
$env:APPDATA = "Roaming"
"$env:USERPROFILE\AppData\LocalLow" = "LocalLow"
}
foreach ($pair in $appDataRoots.GetEnumerator()) {
$root = $pair.Key
$rootName = $pair.Value
if (-not (Test-Path $root)) { continue }
Get-ChildItem $root -Directory -ErrorAction SilentlyContinue | ForEach-Object {
$appName = $_.Name
$appPath = $_.FullName
Get-ChildItem $appPath -Directory -ErrorAction SilentlyContinue | ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($size -gt 50MB) {
[PSCustomObject]@{Scope=$rootName; App=$appName; Subfolder=$_.Name; SizeMB=[math]::Round($size/1MB,1)}
}
}
$fileSize = (Get-ChildItem $appPath -File -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($fileSize -gt 100MB) {
[PSCustomObject]@{Scope=$rootName; App=$appName; Subfolder="(root files)"; SizeMB=[math]::Round($fileSize/1MB,1)}
}
} | Sort-Object SizeMB -Descending | Format-Table -AutoSize
}
This catches SDK caches, portable app data, and abandoned project folders that sit directly in the user's home directory. Many cleanup tools miss this because they only look at AppData.
# 3b-1: Measure ALL directories in user root (hidden + visible), report > 50MB
Get-ChildItem $env:USERPROFILE -Directory -ErrorAction SilentlyContinue -Force | ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($size -gt 50MB) {
$isHidden = ($_.Attributes -band [System.IO.FileAttributes]::Hidden) -eq [System.IO.FileAttributes]::Hidden
$category = if ($_.Name -match '^\.') { "Dev/SDK" }
elseif ($_.Name -eq 'go') { "Go ecosystem" }
elseif ($_.Name -match 'node_modules') { "Node.js" }
elseif ($isHidden) { "Hidden" }
else { "Standard" }
[PSCustomObject]@{Folder=$_.Name; SizeMB=[math]::Round($size/1MB,1); Hidden=$isHidden; Category=$category}
}
} | Sort-Object SizeMB -Descending | Format-Table -AutoSize
# 3b-2: Identify known-cleanable SDK caches (safe to auto-clean later)
Write-Host "`n=== Identifiable SDK caches in user root ==="
$knownCaches = @{
"$env:USERPROFILE\.openjfx\cache" = "JavaFX cache"
"$env:USERPROFILE\.cache" = "XDG cache (Linux-tool cache on Windows)"
"$env:USERPROFILE\go\pkg" = "Go module cache"
"$env:USERPROFILE\.go\pkg" = "Go module cache (hidden)"
"$env:USERPROFILE\.shiv" = "Python shiv tool cache"
"$env:USERPROFILE\.cargo\registry\cache" = "Cargo registry cache"
"$env:USERPROFILE\.gradle\caches" = "Gradle cache"
"$env:USERPROFILE\.m2\repository" = "Maven repo cache"
}
foreach ($pair in $knownCaches.GetEnumerator()) {
if (Test-Path $pair.Key) {
$s = (Get-ChildItem $pair.Key -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 10MB) { Write-Host "$($pair.Value): $([math]::Round($s/1MB,1)) MB — $($pair.Key)" }
}
}
### 3c. Documents Deep Scan
```powershell
Get-ChildItem "$env:USERPROFILE\Documents" -Directory -ErrorAction SilentlyContinue | ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($size -gt 100MB) {
[PSCustomObject]@{Folder=$_.Name; SizeMB=[math]::Round($size/1MB,1)}
}
} | Sort-Object SizeMB -Descending | Format-Table -AutoSize
# Large individual files in Documents
Get-ChildItem "$env:USERPROFILE\Documents" -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.Length -gt 100MB } | Sort-Object Length -Descending | Select-Object -First 20 | ForEach-Object {
Write-Host "$($_.Directory.Name)\$($_.Name): $([math]::Round($_.Length/1MB,1)) MB"
}
# Desktop
Write-Host "=== Desktop ==="
$desktopSize = (Get-ChildItem "$env:USERPROFILE\Desktop" -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
Write-Host "Total: $([math]::Round($desktopSize/1GB,2)) GB"
Get-ChildItem "$env:USERPROFILE\Desktop" -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.Length -gt 20MB } | Sort-Object Length -Descending | Select-Object -First 15 | ForEach-Object {
Write-Host " $($_.Name): $([math]::Round($_.Length/1MB,1)) MB"
}
# Downloads (report only, never auto-clean)
Write-Host "`n=== Downloads ==="
$dlSize = (Get-ChildItem "$env:USERPROFILE\Downloads" -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
Write-Host "Total: $([math]::Round($dlSize/1GB,2)) GB (NOT auto-cleaned — user decision only)"
# Docker
$dockerData = "$env:USERPROFILE\.docker"
$dockerDesktop = "$env:LOCALAPPDATA\Docker"
if ((Test-Path $dockerData) -or (Test-Path $dockerDesktop)) {
Write-Host "Docker detected. Check: docker system df"
docker system df 2>$null
}
# WSL
wsl --list --verbose 2>$null
if (Test-Path "$env:LOCALAPPDATA\Packages") {
$wslDirs = Get-ChildItem "$env:LOCALAPPDATA\Packages" -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match "Canonical|WSL|Debian|Ubuntu|kali" }
foreach ($d in $wslDirs) {
$size = (Get-ChildItem $d.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($size -gt 100MB) { Write-Host "WSL distro $($d.Name): $([math]::Round($size/1GB,2)) GB (VHDX max size, may not represent actual usage)" }
}
}
# OneDrive
$oneDrive = "$env:USERPROFILE\OneDrive"
if (Test-Path $oneDrive) {
$odSize = (Get-ChildItem $oneDrive -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
Write-Host "OneDrive local cache: $([math]::Round($odSize/1GB,2)) GB (use 'Files On-Demand' to free space)"
}
# JetBrains IDEs
$jbDirs = @("$env:LOCALAPPDATA\JetBrains", "$env:APPDATA\JetBrains")
foreach ($jb in $jbDirs) {
if (Test-Path $jb) {
$jbsize = (Get-ChildItem $jb -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "JetBrains: $([math]::Round($jbsize/1GB,2)) GB at $jb"
}
}
# Android Studio / AVD images (can be very large)
$avdDir = "$env:USERPROFILE\.android\avd"
if (Test-Path $avdDir) {
$avdSize = (Get-ChildItem $avdDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($avdSize -gt 100MB) { Write-Host "Android AVD emulator images: $([math]::Round($avdSize/1GB,2)) GB" }
}
# GPU shader caches
foreach ($gpu in @("$env:LOCALAPPDATA\NVIDIA\DXCache", "$env:LOCALAPPDATA\NVIDIA\GLCache",
"$env:LOCALAPPDATA\AMD\DxCache", "$env:LOCALAPPDATA\AMD\GLCache",
"C:\ProgramData\NVIDIA Corporation\NV_Cache")) {
if (Test-Path $gpu) {
$gpuSize = (Get-ChildItem $gpu -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($gpuSize -gt 10MB) { Write-Host "GPU shader cache $gpu : $([math]::Round($gpuSize/1MB,1)) MB" }
}
}
This phase scans for specific junk indicators across the ENTIRE user profile — files and folders that are provably safe to delete but are NOT caught by the generic cache-pattern matching in Phase 5.
Write-Host "=== User profile junk audit ==="
# 3f-1: Squirrel installer versioned app-* folders (old Electron app versions)
Get-ChildItem "$env:LOCALAPPDATA" -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '-full$' } | ForEach-Object {
$s = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 50MB) { Write-Host "Squirrel stale: $($_.FullName) ($([math]::Round($s/1MB,1)) MB)" }
}
# 3f-2: Electron app caches (auto-detect common apps)
foreach ($app in @('Discord', 'Slack', 'Microsoft Teams', 'Spotify', 'Zoom', 'Postman', 'Figma', 'Notion', 'GitHubDesktop')) {
foreach ($scope in @($env:LOCALAPPDATA, $env:APPDATA)) {
$appPath = "$scope\$app"
if (Test-Path $appPath) {
$s = (Get-ChildItem $appPath -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 50MB) { Write-Host "Electron app $app : $([math]::Round($s/1MB,1)) MB at $appPath" }
}
}
}
# 3f-3: iTunes / Apple device backups (can be 10+ GB)
$appleBackup = "$env:APPDATA\Apple Computer\MobileSync\Backup"
if (Test-Path $appleBackup) {
$abSize = (Get-ChildItem $appleBackup -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "Apple device backups: $([math]::Round($abSize/1GB,2)) GB (deleting removes iPhone/iPad backup data)"
}
# 3f-4: INetCache (IE/legacy Edge cache)
$inetCache = "$env:LOCALAPPDATA\Microsoft\Windows\INetCache"
if (Test-Path $inetCache) {
$icSize = (Get-ChildItem $inetCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($icSize -gt 10MB) { Write-Host "INetCache (legacy IE/Edge): $([math]::Round($icSize/1MB,1)) MB" }
}
# 3f-5: Abandoned node_modules folders in user root or shallow subdirs
Get-ChildItem $env:USERPROFILE -Directory -ErrorAction SilentlyContinue -Depth 1 | Where-Object {
$_.Name -eq 'node_modules' -and $_.FullName -notlike '*\AppData\*'
} | ForEach-Object {
$s = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 50MB) { Write-Host "node_modules (non-project): $($_.FullName) ($([math]::Round($s/1MB,1)) MB)" }
}
# 3f-6: Large .log, .tmp, .dump files directly in user root
Get-ChildItem $env:USERPROFILE -File -ErrorAction SilentlyContinue | Where-Object {
$_.Length -gt 50MB -and $_.Extension -in @('.log', '.tmp', '.temp', '.dump', '.dmp', '.etl')
} | ForEach-Object {
Write-Host "Large junk file in user root: $($_.Name) ($([math]::Round($_.Length/1MB,1)) MB)"
}
# 3f-7: Versioned IDE/tool directories (e.g., .vscode/extensions/*/old-versions, .trae-cn)
foreach ($ideDir in @("$env:USERPROFILE\.vscode", "$env:USERPROFILE\.trae-cn",
"$env:USERPROFILE\.cursor", "$env:USERPROFILE\.windsurf")) {
if (-not (Test-Path $ideDir)) { continue }
$ideSize = (Get-ChildItem $ideDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($ideSize -gt 100MB) { Write-Host "IDE data $ideDir : $([math]::Round($ideSize/1MB,1)) MB" }
}
# pip — if installed
if (Get-Command pip -ErrorAction SilentlyContinue) {
pip cache purge 2>&1
}
# Direct folder fallback (works even if pip not on PATH)
@("$env:LOCALAPPDATA\pip\cache", "$env:LOCALAPPDATA\pip\http",
"$env:LOCALAPPDATA\pip\selfcheck") | ForEach-Object {
if (Test-Path $_) {
$s = (Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "pip $(Split-Path $_ -Leaf): $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $_ -ErrorAction SilentlyContinue
}
}
# uv
if (Get-Command uv -ErrorAction SilentlyContinue) { uv cache clean 2>&1 }
if (Test-Path "$env:LOCALAPPDATA\uv\cache") {
$s = (Get-ChildItem "$env:LOCALAPPDATA\uv\cache" -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "uv cache: $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\uv\cache" -ErrorAction SilentlyContinue
}
# npm
if (Get-Command npm -ErrorAction SilentlyContinue) { npm cache clean --force 2>&1 }
# NuGet — clean all cache subdirectories
@("$env:LOCALAPPDATA\NuGet\Cache", "$env:LOCALAPPDATA\NuGet\plugins-cache",
"$env:LOCALAPPDATA\NuGet\http-cache", "$env:LOCALAPPDATA\NuGet\global-packages",
"$env:LOCALAPPDATA\NuGet\v3-cache", "$env:LOCALAPPDATA\NuGet\scratch") | ForEach-Object {
if (Test-Path $_) { Remove-Item -Recurse -Force $_ -ErrorAction SilentlyContinue }
}
# Maven — report, don't auto-clean (redownload is very slow)
if (Test-Path "$env:USERPROFILE\.m2\repository") {
$m2Size = (Get-ChildItem "$env:USERPROFILE\.m2\repository" -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($m2Size -gt 1GB) { Write-Host "NOTE: .m2 Maven cache is $([math]::Round($m2Size/1GB,1)) GB (keeping — re-downloadable but very large)" }
}
# Gradle — only clean jars and transforms, NOT the entire caches folder
if (Test-Path "$env:USERPROFILE\.gradle\caches") {
foreach ($sub in @('jars-9', 'jars-8', 'jars-7', 'transforms-3', 'transforms-2', 'transforms-1', 'build-cache-1')) {
$subPath = "$env:USERPROFILE\.gradle\caches\$sub"
if (Test-Path $subPath) {
$gs = (Get-ChildItem $subPath -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($gs -gt 100MB) {
Write-Host "Gradle $sub: $([math]::Round($gs/1MB,1)) MB"
Remove-Item -Recurse -Force $subPath -ErrorAction SilentlyContinue
}
}
}
}
$freed = 0
# Temp directories
@("$env:TEMP", "C:\Windows\Temp") | ForEach-Object {
if (Test-Path $_) {
$before = (Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue 2>$null
$after = (Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
$diff = $before - $after
$freed += $diff
Write-Host "$_ : $([math]::Round($diff/1MB,1)) MB"
}
}
# Prefetch
$pfBefore = (Get-ChildItem C:\Windows\Prefetch\*.pf -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
Get-ChildItem C:\Windows\Prefetch\*.pf -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
$freed += $pfBefore
Write-Host "Prefetch: $([math]::Round($pfBefore/1MB,1)) MB"
# Thumbnail cache
$thumbBefore = (Get-ChildItem "$env:LOCALAPPDATA\Microsoft\Windows\Explorer" -Filter "thumbcache_*" -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
Get-ChildItem "$env:LOCALAPPDATA\Microsoft\Windows\Explorer" -Filter "thumbcache_*" -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
$freed += $thumbBefore
# Font cache
$fontDir = "$env:LOCALAPPDATA\Microsoft\Windows\Fonts"
if (Test-Path $fontDir) {
$fontBefore = (Get-ChildItem $fontDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Get-ChildItem $fontDir -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
$freed += $fontBefore
Write-Host "Font cache: $([math]::Round($fontBefore/1MB,1)) MB"
}
# DNS cache
ipconfig /flushdns 2>$null
# Recycle Bin
Clear-RecycleBin -Force -ErrorAction SilentlyContinue
Write-Host "Recycle Bin emptied"
# Windows Panther setup logs
if (Test-Path C:\Windows\Panther\monitor) {
$pmSize = (Get-ChildItem C:\Windows\Panther\monitor -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Get-ChildItem C:\Windows\Panther\monitor -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
$freed += $pmSize
Write-Host "Panther monitor logs: $([math]::Round($pmSize/1MB,1)) MB"
}
Get-ChildItem C:\Windows\Panther -File -ErrorAction SilentlyContinue | Where-Object { $_.Extension -match '\.(log|etl|txt)$' } | ForEach-Object {
$freed += $_.Length; Remove-Item $_.FullName -Force
}
# Delivery Optimization
$doDir = "C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization"
if (Test-Path $doDir) {
$doSize = (Get-ChildItem $doDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Get-ChildItem $doDir -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
$freed += $doSize
}
# Windows Update download cache
$wuDir = "C:\Windows\SoftwareDistribution\Download"
if (Test-Path $wuDir) {
$wuS = (Get-ChildItem $wuDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Get-ChildItem $wuDir -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
$freed += $wuS
Write-Host "Windows Update cache: $([math]::Round($wuS/1MB,1)) MB"
}
# Old CBS persist logs (keep current CBS.log)
Get-ChildItem C:\Windows\Logs\CBS -Filter "CbsPersist_*.log" -ErrorAction SilentlyContinue | ForEach-Object {
$freed += $_.Length; Remove-Item $_ -Force
}
# DISM logs > 10MB
Get-ChildItem C:\Windows\Logs\DISM -Filter "dism*.log" -ErrorAction SilentlyContinue | Where-Object { $_.Length -gt 10MB } | ForEach-Object {
$freed += $_.Length; Remove-Item $_ -Force
}
# Windows Error Reporting
$werDir = "C:\ProgramData\Microsoft\Windows\WER"
if (Test-Path $werDir) {
$werS = (Get-ChildItem $werDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($werS -gt 10MB) {
Get-ChildItem $werDir -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
$freed += $werS
Write-Host "WER: $([math]::Round($werS/1MB,1)) MB"
}
}
# Live Kernel Reports
$lkDir = "C:\Windows\LiveKernelReports"
if (Test-Path $lkDir) {
$lkSize = (Get-ChildItem $lkDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($lkSize -gt 10MB) {
Get-ChildItem $lkDir -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
$freed += $lkSize
Write-Host "LiveKernelReports: $([math]::Round($lkSize/1MB,1)) MB"
}
}
Write-Host "`nPhase 4b total: $([math]::Round($freed/1MB,1)) MB"
# Report this number so the LLM can use it in the final summary
Write-Host "PHASE4B_FREED=$([math]::Round($freed/1MB,1))"
Write-Host "DISM basic cleanup..."
dism /online /cleanup-image /startcomponentcleanup
Write-Host "DISM deep cleanup (/resetbase) — removes ALL superseded components."
Write-Host "WARNING: After /resetbase, you cannot uninstall Windows updates. This is generally fine."
dism /online /cleanup-image /startcomponentcleanup /resetbase
Write-Host "Resizing VSS to 1GB max..."
vssadmin resize shadowstorage /for=C: /on=C: /maxsize=1GB
vssadmin list shadowstorage
# Report only — do NOT auto-delete
$installerDir = "C:\Windows\Installer"
if (Test-Path $installerDir) {
$instSize = (Get-ChildItem $installerDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "Windows Installer cache: $([math]::Round($instSize/1GB,2)) GB (not auto-cleaned — if > 2GB, flag as manual cleanup item)"
}
-contains, never substring matching.git, package.json, Cargo.toml, CMakeLists.txt, or README-Depth 8 from AppData roots# EXACT directory names that are universally safe cache folders
$safePatterns = @(
'Cache', 'cache', 'CACHE',
'Temp', 'temp', 'TEMP',
'Log', 'Logs', 'log', 'logs',
'Code Cache',
'GPUCache',
'DawnCache',
'ShaderCache',
'GrShaderCache',
'Crashpad',
'CrashDumps',
'Crash Reports',
'thumbnails', 'Thumbnails',
'preview', 'Preview',
'__pycache__'
)
$searchRoots = @($env:LOCALAPPDATA, $env:APPDATA, "$env:USERPROFILE\AppData\LocalLow", "$env:USERPROFILE\.vscode")
$totalFreed = 0
foreach ($root in $searchRoots) {
if (-not (Test-Path $root)) { continue }
Get-ChildItem $root -Recurse -Directory -ErrorAction SilentlyContinue -Depth 8 | Where-Object {
$safePatterns -contains $_.Name
} | ForEach-Object {
# Safety: skip project directories
$isProject = (Test-Path "$($_.FullName)\.git") -or
(Test-Path "$($_.FullName)\package.json") -or
(Test-Path "$($_.FullName)\Cargo.toml") -or
(Test-Path "$($_.FullName)\CMakeLists.txt") -or
(Test-Path "$($_.FullName)\README") -or
(Test-Path "$($_.FullName)\README.md")
if ($isProject) { return }
# Safety: skip reparse points
$item = Get-Item $_.FullName -ErrorAction SilentlyContinue
if ($item.LinkType) { return }
$size = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
if ($size -gt 1MB) {
Write-Host "Cache: $($_.FullName) ($([math]::Round($size/1MB,1)) MB)"
$totalFreed += $size
Remove-Item -Recurse -Force $_.FullName -ErrorAction SilentlyContinue
}
}
}
Write-Host "`nPhase 5a total: $([math]::Round($totalFreed/1MB,1)) MB"
Write-Host "PHASE5A_FREED=$([math]::Round($totalFreed/1MB,1))"
$gpuFreed = 0
foreach ($gpuPath in @(
"$env:LOCALAPPDATA\NVIDIA\DXCache",
"$env:LOCALAPPDATA\NVIDIA\GLCache",
"$env:LOCALAPPDATA\AMD\DxCache",
"$env:LOCALAPPDATA\AMD\GLCache",
"$env:LOCALAPPDATA\AMD\VkCache",
"$env:PROGRAMDATA\NVIDIA Corporation\NV_Cache"
)) {
if (Test-Path $gpuPath) {
$gs = (Get-ChildItem $gpuPath -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($gs -gt 5MB) {
Write-Host "GPU cache $gpuPath : $([math]::Round($gs/1MB,1)) MB"
$gpuFreed += $gs
Get-ChildItem $gpuPath -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
}
}
}
Write-Host "GPU shader caches: $([math]::Round($gpuFreed/1MB,1)) MB"
$browserFreed = 0
# --- Chromium-based browsers (auto-discover) ---
$browserDataDirs = @()
foreach ($vendor in @('Google', 'Microsoft', 'BraveSoftware', 'Opera Software')) {
$vendorPath = "$env:LOCALAPPDATA\$vendor"
if (Test-Path $vendorPath) {
Get-ChildItem $vendorPath -Directory -ErrorAction SilentlyContinue | ForEach-Object {
$userData = "$($_.FullName)\User Data"
if (Test-Path $userData) { $browserDataDirs += $userData }
}
}
}
foreach ($userData in $browserDataDirs) {
Write-Host "Chromium browser: $userData"
# Per-profile caches
Get-ChildItem $userData -Directory -ErrorAction SilentlyContinue | ForEach-Object {
foreach ($cacheName in @('Cache', 'Code Cache', 'Service Worker', 'GPUCache',
'DawnCache', 'ShaderCache', 'GrShaderCache', 'Crashpad')) {
$cp = "$($_.FullName)\$cacheName"
if (Test-Path $cp) {
$s = (Get-ChildItem $cp -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
$browserFreed += $s
Remove-Item -Recurse -Force $cp -ErrorAction SilentlyContinue
}
}
}
# Global caches (names not in 5a pattern list)
foreach ($cacheName in @('extensions_crx_cache', 'component_crx_cache', 'SODALanguagePacks',
'optimization_guide_model_store', 'WasmTtsEngine', 'SwReporter',
'Snapshots', 'segmentation_platform', 'MediaFoundationWidevineCdm')) {
$gp = "$userData\$cacheName"
if (Test-Path $gp) {
$s = (Get-ChildItem $gp -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
$browserFreed += $s
Write-Host " $cacheName : $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $gp -ErrorAction SilentlyContinue
}
}
}
# --- Firefox ---
$firefoxProfiles = @(
"$env:APPDATA\Mozilla\Firefox\Profiles",
"$env:LOCALAPPDATA\Mozilla\Firefox\Profiles"
)
foreach ($ffRoot in $firefoxProfiles) {
if (-not (Test-Path $ffRoot)) { continue }
Get-ChildItem $ffRoot -Directory -ErrorAction SilentlyContinue | ForEach-Object {
foreach ($ffCache in @('cache2', 'startupCache', 'thumbnails', 'safebrowsing')) {
$ffPath = "$($_.FullName)\$ffCache"
if (Test-Path $ffPath) {
$s = (Get-ChildItem $ffPath -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 1MB) {
$browserFreed += $s
Write-Host "Firefox $ffCache : $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $ffPath -ErrorAction SilentlyContinue
}
}
}
# Firefox storage (can be large)
$ffStorage = "$($_.FullName)\storage\default"
if (Test-Path $ffStorage) {
$s = (Get-ChildItem $ffStorage -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 50MB) {
Write-Host "Firefox storage/default: $([math]::Round($s/1MB,1)) MB (caution: may contain extension data — flag to user)"
# Don't auto-clean storage — may contain extension data
}
}
}
}
Write-Host "Browser caches: $([math]::Round($browserFreed/1MB,1)) MB"
$jbLocal = "$env:LOCALAPPDATA\JetBrains"
if (Test-Path $jbLocal) {
Get-ChildItem $jbLocal -Directory -ErrorAction SilentlyContinue | ForEach-Object {
# Clean caches
$cacheDir = "$($_.FullName)\caches"
if (Test-Path $cacheDir) {
$s = (Get-ChildItem $cacheDir -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "JetBrains $($_.Name) caches: $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $cacheDir -ErrorAction SilentlyContinue
}
# Clean old product version directories
Get-ChildItem $_.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^\d+\.\d+' } | ForEach-Object {
$s = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "JetBrains old version $($_.Name): $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $_.FullName -ErrorAction SilentlyContinue
}
}
}
foreach ($vsc in @('Code', 'Code - Insiders', 'Code - Exploration')) {
$vscRoot = "$env:APPDATA\$vsc"
if (-not (Test-Path $vscRoot)) { continue }
foreach ($sub in @('Cache', 'CachedData', 'Code Cache', 'GPUCache', 'Crashpad',
'DawnCache', 'ShaderCache', 'GrShaderCache')) {
$cp = "$vscRoot\$sub"
if (Test-Path $cp) {
$s = (Get-ChildItem $cp -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "$vsc $sub: $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $cp -ErrorAction SilentlyContinue
}
}
# Workspace storage (contains cached workspace state, safe to clean)
$wsStorage = "$vscRoot\User\workspaceStorage"
if (Test-Path $wsStorage) {
$wsSize = (Get-ChildItem $wsStorage -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($wsSize -gt 200MB) {
Write-Host "$vsc workspaceStorage: $([math]::Round($wsSize/1MB,1)) MB"
Remove-Item -Recurse -Force $wsStorage -ErrorAction SilentlyContinue
}
}
}
# Find SQLite/DB files with I/O error markers — unrecoverable
Get-ChildItem $env:USERPROFILE -Recurse -File -ErrorAction SilentlyContinue -Depth 6 | Where-Object {
$_.Name -match 'SQLITE_IOERR|SQLITE_CORRUPT|_IOERR\d{10,}'
} | ForEach-Object {
Write-Host "Corrupted DB: $($_.FullName) ($([math]::Round($_.Length/1MB,1)) MB)"
Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
}
# Orphaned WAL/SHM journal files (parent DB no longer exists)
Get-ChildItem $env:USERPROFILE -Recurse -File -ErrorAction SilentlyContinue -Depth 6 | Where-Object {
$ext = $_.Extension
($ext -eq '.db-wal' -or $ext -eq '.db-shm' -or $ext -eq '.db-journal') -and
(-not (Test-Path ($_.FullName -replace '-(wal|shm|journal)$', '')))
} | ForEach-Object {
Write-Host "Orphaned journal: $($_.FullName) ($([math]::Round($_.Length/1MB,1)) MB)"
Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
}
$desktop = "$env:USERPROFILE\Desktop"
# Known junk: update archives, Tor cached data, Office temp files
$junkPatterns = @('update.mar', 'update.mar.*', 'cached-microdescs', 'cached-certs',
'*.tmp', '*.temp', '~$*.docx', '~$*.xlsx', '~$*.pptx')
foreach ($pattern in $junkPatterns) {
Get-ChildItem $desktop -Filter $pattern -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.Length -gt 10MB -or $_.Extension -match '\.(tmp|temp|mar)$') {
Write-Host "Desktop junk: $($_.Name) ($([math]::Round($_.Length/1MB,1)) MB)"
Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
}
}
}
@("C:\tmp", "C:\temp") | ForEach-Object {
if (Test-Path $_) {
Get-ChildItem $_ -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
$ext = $_.Extension.ToLower()
if ($ext -in @('.log', '.tmp', '.temp', '.dump', '.etl', '.txt') -and $_.Length -gt 10MB) {
$firstLine = Get-Content $_.FullName -TotalCount 1 -ErrorAction SilentlyContinue
if ($firstLine -match 'TLS secrets|# TLS|SSLKEYLOGFILE|DEBUG|TRACE|PresharedKey|Generated by') {
Write-Host "Debug log: $($_.FullName) ($([math]::Round($_.Length/1MB,1)) MB)"
Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
}
}
}
}
}
These are re-downloadable build caches sitting directly in $env:USERPROFILE, outside AppData. Phase 3b identified them; now clean them.
# JavaFX SDK cache
$jfxCache = "$env:USERPROFILE\.openjfx\cache"
if (Test-Path $jfxCache) {
$s = (Get-ChildItem $jfxCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host ".openjfx cache: $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $jfxCache -ErrorAction SilentlyContinue
}
# XDG .cache directory (used by Git Bash, MSYS2, Cygwin, Linux-tool ports)
$xdgCache = "$env:USERPROFILE\.cache"
if (Test-Path $xdgCache) {
$s = (Get-ChildItem $xdgCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 5MB) {
Write-Host ".cache (XDG): $([math]::Round($s/1MB,1)) MB"
Get-ChildItem $xdgCache -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
}
}
# Go module cache (go/pkg/mod)
$goModCache = "$env:USERPROFILE\go\pkg\mod"
if (-not (Test-Path $goModCache)) { $goModCache = "$env:USERPROFILE\.go\pkg\mod" }
if (Test-Path $goModCache) {
$s = (Get-ChildItem $goModCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "Go module cache: $([math]::Round($s/1MB,1)) MB (use 'go clean -modcache' if Go is installed)"
# Use go clean if available, otherwise manual
if (Get-Command go -ErrorAction SilentlyContinue) {
go clean -modcache 2>&1
} else {
Remove-Item -Recurse -Force $goModCache -ErrorAction SilentlyContinue
}
}
# Python shiv tool cache
$shivCache = "$env:USERPROFILE\.shiv"
if (Test-Path $shivCache) {
$s = (Get-ChildItem $shivCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host ".shiv cache: $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $shivCache -ErrorAction SilentlyContinue
}
# Cargo registry cache (Rust)
$cargoRegCache = "$env:USERPROFILE\.cargo\registry\cache"
if (Test-Path $cargoRegCache) {
$s = (Get-ChildItem $cargoRegCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
Write-Host "Cargo registry cache: $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $cargoRegCache -ErrorAction SilentlyContinue
}
Squirrel-based apps (Teams, Slack, Discord, WhatsApp Desktop, etc.) leave app-x.x.x or app-x.x.x-full versioned directories after auto-updates. Only the CURRENT version is needed.
# Clean stale Squirrel install folders in LocalAppData
Get-ChildItem "$env:LOCALAPPDATA" -Directory -ErrorAction SilentlyContinue | Where-Object {
$_.Name -match '-full$'
} | ForEach-Object {
$s = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 50MB) {
Write-Host "Squirrel stale: $($_.Name) ($([math]::Round($s/1MB,1)) MB)"
Remove-Item -Recurse -Force $_.FullName -ErrorAction SilentlyContinue
}
}
# Clean old version-numbered app subdirectories (e.g., app-1.2.3 within an Electron app)
foreach ($electronApp in @('Discord', 'Slack', 'Microsoft Teams', 'Spotify', 'GitHubDesktop')) {
$appDir = "$env:LOCALAPPDATA\$electronApp"
if (-not (Test-Path $appDir)) { continue }
Get-ChildItem $appDir -Directory -ErrorAction SilentlyContinue | Where-Object {
$_.Name -match '^app-\d+\.\d+\.\d+'
} | ForEach-Object {
$s = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
# Keep only if it looks like the active version (check if parent exe references it)
if ($s -gt 30MB) {
Write-Host "Electron old version $electronApp\$($_.Name): $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $_.FullName -ErrorAction SilentlyContinue
}
}
}
# INetCache (IE / legacy Edge cache)
$inetCache = "$env:LOCALAPPDATA\Microsoft\Windows\INetCache"
if (Test-Path $inetCache) {
$s = (Get-ChildItem $inetCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 5MB) {
Write-Host "INetCache: $([math]::Round($s/1MB,1)) MB"
Get-ChildItem $inetCache -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
}
}
# IE Cookies and History (safe to clear)
foreach ($ieDir in @("$env:LOCALAPPDATA\Microsoft\Windows\INetCookies",
"$env:LOCALAPPDATA\Microsoft\Windows\History")) {
if (Test-Path $ieDir) {
Get-ChildItem $ieDir -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue 2>$null
}
}
# Flash cache (deprecated but may still exist)
$flashCache = "$env:APPDATA\Macromedia\Flash Player"
if (Test-Path $flashCache) {
$s = (Get-ChildItem $flashCache -Recurse -ErrorAction SilentlyContinue | Where-Object { !$_.PSIsContainer } | Measure-Object -Property Length -Sum).Sum
if ($s -gt 5MB) {
Write-Host "Flash Player cache: $([math]::Round($s/1MB,1)) MB"
Remove-Item -Recurse -Force $flashCache -ErrorAction SilentlyContinue
}
}
After Phases 4-5, remaining large items are user data, not cache. Categorize and present:
For each remaining folder > 200MB from Phase 3:
| Path Pattern | Category | Recommendation |
|---|---|---|
Contains \Msg\, \messages\, \chat\ | Chat data | User's chat history — ask |
Contains BackupFiles, \Backup\, _backup | Old backups | Redundant — suggest deletion |
.rustup\toolchains | SDK toolchains | Reinstallable — suggest keeping only active one |
.cargo, .gradle, .m2, .nuget | Build cache | Re-downloadable — suggest cleaning |
\Projects\, \Workspace\, \repos\ | Dev projects | NEVER suggest deletion |
\Recordings\, \Meetings\ | Recordings | May be important — ask |
VirtualBox, VMware, Docker, WSL | VM/Container | May be important — ask |
BurpSuite, Wireshark, fiddler, ZAP | Security tools | User projects — NEVER delete |
.android\avd | Android emulators | Re-downloadable but large — ask |
.apple, MobileSync, Apple Computer | Apple backups | May be important — ask |
Squirrel, app-, -full | Old installers | Stale versions — suggest deletion |
node_modules (in user root, not in a project) | Abandoned deps | Can be regenerated — suggest deletion |
go/pkg, .go/pkg | Go module cache | Re-downloadable — suggest cleaning |
.cache, .shiv, .openjfx | SDK/tool cache | Safe to delete — suggest cleaning |
IntelGraphicsProfiles, Intel in LocalLow | GPU driver cache | Safe to delete — auto-clean |
| Unknown (can't classify) | Unknown | Err on caution — NEVER delete |
Present as a table:
### Items for Your Decision (X.XX GB total)
| # | Path | Size | Category | Risk | Note |
|---|------|------|----------|------|------|
| 1 | <path> | X.XX GB | <category> | Low | <suggestion> |
Ask: "Enter numbers to clean (e.g., 1,3,5), or 'all' / 'none'."
Write-Host "========================================"
Write-Host " FINAL DISK CLEANUP REPORT"
Write-Host "========================================"
Get-PSDrive C | ForEach-Object {
$total = [math]::Round(($_.Used + $_.Free)/1GB, 2)
$used = [math]::Round($_.Used/1GB, 2)
$free = [math]::Round($_.Free/1GB, 2)
$pct = [math]::Round($_.Used/($_.Used+$_.Free)*100, 1)
Write-Host "Total: $total GB | Used: $used GB ($pct%) | Free: $free GB"
}
Write-Host "========================================"
After the PowerShell output, manually compile a summary table from the PHASE*_FREED markers and per-phase notes:
Cleanup Summary:
4a Package managers: X.XX GB
4b Windows junk: X.XX GB
4c DISM: completed
4d VSS resize: completed
5a Pattern caches: X.XX GB
5b GPU shader caches: X.XX GB
5c Browser caches: X.XX GB
5d JetBrains caches: X.XX GB
5e VS Code caches: X.XX GB
5f Corrupted DB files: X.XX GB
5g Desktop junk: X.XX GB
5h Root orphans: X.XX GB
─────────────────────────────
TOTAL FREED: X.XX GB
Also list remaining large directories with explanations for why they were kept.
-ErrorAction SilentlyContinue everywhere — locked files are skipped!$_.PSIsContainer (PowerShell 5.1 compatible)-contains for exact name matching; never -match with partial patterns