Created
February 13, 2026 03:20
-
-
Save lirrensi/4eda18d6fcc0ea6b491f7bdc829722d4 to your computer and use it in GitHub Desktop.
PWSH script to shink overgrown WSL and reclaim disk space. Finds all containers and removes free space made by autogrow. Warning: may kill your wsl! Close first pls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # WSL VHDX Shrink Script | |
| # This fancy lil script will save ur precious space cause microslop geniuses forgot that auto-growing disks need periodic compaction. | |
| $ErrorActionPreference = "Stop" | |
| # Check if running as admin | |
| $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) | |
| if (-not $isAdmin) { | |
| Write-Host "`nβ Not running as Administrator. Come on, really?" -ForegroundColor Red | |
| Write-Host "Right-click and 'Run as Administrator' like a normal person.`n" -ForegroundColor Yellow | |
| exit 1 | |
| } | |
| # Find all VHDX files in AppData | |
| Write-Host "`nπ Searching for VHDX files..." -ForegroundColor Cyan | |
| Write-Host "This might take a moment because AppData is a dumpster fire...`n" -ForegroundColor DarkGray | |
| # Scan entire LOCALAPPDATA for VHDX files | |
| $vhdxFiles = Get-ChildItem -Path $env:LOCALAPPDATA -Filter "*.vhdx" -Recurse -ErrorAction SilentlyContinue -Force | |
| if ($vhdxFiles.Count -eq 0) { | |
| Write-Host "β No VHDX files found. Do you even have WSL installed?" -ForegroundColor Red | |
| exit 1 | |
| } | |
| Write-Host "β Found $($vhdxFiles.Count) VHDX file(s)`n" -ForegroundColor Green | |
| # Build selection list with sizes | |
| $vhdxList = @() | |
| foreach ($file in $vhdxFiles) { | |
| $sizeGB = [math]::Round($file.Length / 1GB, 2) | |
| $vhdxList += @{ | |
| Path = $file.FullName | |
| Name = $file.Name | |
| Directory = $file.DirectoryName | |
| SizeGB = $sizeGB | |
| } | |
| } | |
| # Add "Compact All" option | |
| $vhdxList += @{ | |
| Path = "ALL" | |
| Name = "Compact All VHDX Files" | |
| Directory = "" | |
| SizeGB = $vhdxList.Count | |
| } | |
| # Arrow key selection menu | |
| $currentIndex = 0 | |
| $maxIndex = $vhdxList.Count - 1 | |
| function Show-Menu { | |
| param($index) | |
| Clear-Host | |
| Write-Host "`nπ Select a VHDX file to shrink (Use ββ arrows, Enter to select):" -ForegroundColor Yellow | |
| Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor DarkGray | |
| for ($i = 0; $i -lt $vhdxList.Count; $i++) { | |
| $vhdx = $vhdxList[$i] | |
| $prefix = if ($i -eq $index) { "βΆ " } else { " " } | |
| $color = if ($i -eq $index) { "Green" } else { "White" } | |
| if ($vhdx.Path -eq "ALL") { | |
| Write-Host "$prefixπ₯ Compact All $($vhdx.SizeGB) VHDX Files" -ForegroundColor $color | |
| } else { | |
| Write-Host "$prefixπΎ $($vhdx.Name) - $($vhdx.SizeGB) GB" -ForegroundColor $color | |
| if ($i -eq $index) { | |
| Write-Host " π $($vhdx.Directory)" -ForegroundColor DarkGray | |
| } | |
| } | |
| } | |
| Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor DarkGray | |
| } | |
| # Menu loop | |
| while ($true) { | |
| Show-Menu -index $currentIndex | |
| $key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | |
| switch ($key.VirtualKeyCode) { | |
| 38 { # Up arrow | |
| if ($currentIndex -gt 0) { $currentIndex-- } | |
| } | |
| 40 { # Down arrow | |
| if ($currentIndex -lt $maxIndex) { $currentIndex++ } | |
| } | |
| 13 { # Enter | |
| $selectedVHDX = $vhdxList[$currentIndex] | |
| break | |
| } | |
| } | |
| if ($key.VirtualKeyCode -eq 13) { break } | |
| } | |
| Clear-Host | |
| if ($selectedVHDX.Path -eq "ALL") { | |
| Write-Host "`nπ₯ Selected: Compact All VHDX Files" -ForegroundColor Green | |
| Write-Host "π Count: $($selectedVHDX.SizeGB) files" -ForegroundColor White | |
| } else { | |
| Write-Host "`nβ Selected: $($selectedVHDX.Name)" -ForegroundColor Green | |
| Write-Host "π Path: $($selectedVHDX.Path)" -ForegroundColor White | |
| Write-Host "πΎ Current size: $($selectedVHDX.SizeGB) GB`n" -ForegroundColor Yellow | |
| } | |
| # Step 1: Shutdown ALL WSL instances | |
| Write-Host "βΉοΈ Shutting down all WSL instances..." -ForegroundColor Cyan | |
| Write-Host "(If WSL is running, this will kill it. Save your work!)`n" -ForegroundColor Yellow | |
| # Add confirmation prompt | |
| Write-Host "β Are you sure you want to shut down all WSL instances?" -ForegroundColor Yellow | |
| $confirmation = Read-Host "Type 'YES' to confirm, anything else to cancel" | |
| if ($confirmation -ne "YES") { | |
| Write-Host "β Operation cancelled by user." -ForegroundColor Red | |
| exit 1 | |
| } | |
| Start-Sleep -Seconds 2 | |
| try { | |
| wsl --shutdown | |
| Start-Sleep -Seconds 3 | |
| Write-Host "β WSL shut down`n" -ForegroundColor Green | |
| } catch { | |
| Write-Host "β οΈ WSL shutdown failed, but we'll try anyway..." -ForegroundColor Yellow | |
| } | |
| # Step 2: Optimize/Shrink VHDX | |
| if ($selectedVHDX.Path -eq "ALL") { | |
| Write-Host "ποΈ Compacting ALL VHDX files..." -ForegroundColor Cyan | |
| Write-Host "This might take a while. Go touch grass or something.`n" -ForegroundColor DarkGray | |
| # Compact all VHDX files | |
| foreach ($vhdx in $vhdxList) { | |
| if ($vhdx.Path -ne "ALL") { | |
| Write-Host "Processing: $($vhdx.Name) - $($vhdx.SizeGB) GB" -ForegroundColor Yellow | |
| $diskpartScript = @" | |
| select vdisk file="$($vhdx.Path)" | |
| attach vdisk readonly | |
| compact vdisk | |
| detach vdisk | |
| exit | |
| "@ | |
| $scriptPath = "$env:TEMP\diskpart_shrink_$(Get-Random).txt" | |
| $diskpartScript | Out-File -FilePath $scriptPath -Encoding ASCII | |
| try { | |
| $result = diskpart /s $scriptPath 2>&1 | |
| # Check if diskpart actually succeeded | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "β $($vhdx.Name) compacted successfully!" -ForegroundColor Green | |
| } else { | |
| Write-Host "β Failed to compact $($vhdx.Name)" -ForegroundColor Red | |
| Write-Host "Output: $result" -ForegroundColor DarkGray | |
| } | |
| } catch { | |
| Write-Host "β Something went wrong with $($vhdx.Name): $_" -ForegroundColor Red | |
| } finally { | |
| Remove-Item $scriptPath -ErrorAction SilentlyContinue | |
| } | |
| } | |
| } | |
| } else { | |
| Write-Host "ποΈ Shrinking VHDX..." -ForegroundColor Cyan | |
| Write-Host "This might take a minute. Go touch grass or something.`n" -ForegroundColor DarkGray | |
| $vhdxPath = $selectedVHDX.Path | |
| $diskpartScript = @" | |
| select vdisk file="$vhdxPath" | |
| attach vdisk readonly | |
| compact vdisk | |
| detach vdisk | |
| exit | |
| "@ | |
| $scriptPath = "$env:TEMP\diskpart_shrink_$(Get-Random).txt" | |
| $diskpartScript | Out-File -FilePath $scriptPath -Encoding ASCII | |
| try { | |
| $result = diskpart /s $scriptPath 2>&1 | |
| # Check if diskpart actually succeeded | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "β VHDX shrunk successfully!`n" -ForegroundColor Green | |
| } else { | |
| Write-Host "β Diskpart failed with exit code: $LASTEXITCODE" -ForegroundColor Red | |
| Write-Host "Output: $result" -ForegroundColor DarkGray | |
| throw "Diskpart operation failed" | |
| } | |
| } catch { | |
| Write-Host "β Something went wrong. The disk gods are angry." -ForegroundColor Red | |
| Write-Host "Error: $_" -ForegroundColor Red | |
| exit 1 | |
| } finally { | |
| Remove-Item $scriptPath -ErrorAction SilentlyContinue | |
| } | |
| } | |
| # Show results | |
| if ($selectedVHDX.Path -ne "ALL") { | |
| $sizeAfter = [math]::Round((Get-Item $vhdxPath).Length / 1GB, 2) | |
| $saved = [math]::Round($selectedVHDX.SizeGB - $sizeAfter, 2) | |
| Write-Host "βββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Green | |
| Write-Host "π RESULTS:" -ForegroundColor Cyan | |
| Write-Host " Before: $($selectedVHDX.SizeGB) GB" -ForegroundColor White | |
| Write-Host " After: $sizeAfter GB" -ForegroundColor White | |
| if ($saved -gt 0) { | |
| Write-Host " Saved: $saved GB π" -ForegroundColor Green | |
| } else { | |
| Write-Host " Saved: $saved GB (lol nothing)" -ForegroundColor Yellow | |
| } | |
| Write-Host "βββββββββββββββββββββββββββββββββββββββββββββ`n" -ForegroundColor Green | |
| } else { | |
| Write-Host "βββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Green | |
| Write-Host "π RESULTS:" -ForegroundColor Cyan | |
| Write-Host " Processed $($selectedVHDX.SizeGB) VHDX files" -ForegroundColor White | |
| Write-Host " All files have been compacted" -ForegroundColor Green | |
| Write-Host "βββββββββββββββββββββββββββββββββββββββββββββ`n" -ForegroundColor Green | |
| } | |
| Write-Host "β¨ All done! Your disk is slightly less full.`n" -ForegroundColor Green |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment