Last active
February 6, 2026 06:23
-
-
Save Satal/758320d5b5d9eb51267aedb4371ae174 to your computer and use it in GitHub Desktop.
Ubuntu Cleanup Script
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
| #Requires -RunAsAdministrator | |
| <# | |
| .SYNOPSIS | |
| Compresses/shrinks a WSL2 virtual disk (VHDX) to reclaim unused space. | |
| .DESCRIPTION | |
| Cleans up inside WSL, trims free space, shuts down WSL, then compacts | |
| the VHDX file using either Optimize-VHD or diskpart as a fallback. | |
| .PARAMETER SkipCleanup | |
| Skip the internal WSL cleanup step (apt clean, temp files, Docker prune). | |
| .PARAMETER Distro | |
| WSL distribution name to target. Defaults to the default distribution. | |
| #> | |
| param( | |
| [switch]$SkipCleanup, | |
| [string]$Distro | |
| ) | |
| $ErrorActionPreference = "Stop" | |
| Write-Host "`n=== WSL2 Disk Compaction ===" -ForegroundColor Cyan | |
| Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`n" | |
| # --- Step 1: Locate the VHDX file --- | |
| Write-Host "[1/7] Locating VHDX file..." -ForegroundColor Yellow | |
| $vhdxFiles = Get-ChildItem -Path "$env:USERPROFILE\AppData\Local\Packages" ` | |
| -Recurse -Filter "ext4.vhdx" -ErrorAction SilentlyContinue | |
| if (-not $vhdxFiles) { | |
| Write-Error "No ext4.vhdx file found. Is WSL2 installed?" | |
| exit 1 | |
| } | |
| # If multiple VHDX files found, let user know | |
| if ($vhdxFiles.Count -gt 1) { | |
| Write-Host " Found multiple VHDX files:" -ForegroundColor DarkYellow | |
| $vhdxFiles | ForEach-Object { | |
| Write-Host " $($_.FullName) - $([math]::Round($_.Length/1GB,2)) GB" | |
| } | |
| Write-Host " Processing all of them...`n" | |
| } else { | |
| Write-Host " Found: $($vhdxFiles[0].FullName)" -ForegroundColor Gray | |
| } | |
| $beforeSizes = @{} | |
| foreach ($vhdx in $vhdxFiles) { | |
| $sizeGB = [math]::Round($vhdx.Length / 1GB, 2) | |
| $beforeSizes[$vhdx.FullName] = $sizeGB | |
| Write-Host " Current size: $sizeGB GB" -ForegroundColor Gray | |
| } | |
| # --- Step 2: Clean up inside WSL (while it's running) --- | |
| if (-not $SkipCleanup) { | |
| Write-Host "`n[2/7] Cleaning up inside WSL..." -ForegroundColor Yellow | |
| $wslCmd = if ($Distro) { "wsl -d $Distro" } else { "wsl" } | |
| $cleanupScript = @" | |
| sudo apt autoremove -y 2>/dev/null && sudo apt clean 2>/dev/null | |
| sudo rm -rf /tmp/* 2>/dev/null | |
| sudo journalctl --vacuum-time=3d 2>/dev/null | |
| if command -v docker &>/dev/null; then docker system prune -af --volumes 2>/dev/null; fi | |
| echo 'Cleanup complete' | |
| "@ | |
| if ($Distro) { | |
| wsl -d $Distro -- bash -c $cleanupScript | |
| } else { | |
| wsl -- bash -c $cleanupScript | |
| } | |
| Write-Host " Done." -ForegroundColor Gray | |
| } else { | |
| Write-Host "`n[2/7] Skipping cleanup (SkipCleanup flag set)" -ForegroundColor DarkGray | |
| } | |
| # --- Step 3: Zero out free space with fstrim --- | |
| Write-Host "`n[3/7] Trimming free space (fstrim)..." -ForegroundColor Yellow | |
| if ($Distro) { | |
| wsl -d $Distro -- sudo fstrim / 2>$null | |
| } else { | |
| wsl -- sudo fstrim / 2>$null | |
| } | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host " Done." -ForegroundColor Gray | |
| } else { | |
| Write-Host " fstrim not supported on this build - skipping (compaction will still work)." -ForegroundColor DarkYellow | |
| } | |
| # --- Step 4: Shut down WSL --- | |
| Write-Host "`n[4/7] Shutting down WSL..." -ForegroundColor Yellow | |
| wsl --shutdown | |
| Start-Sleep -Seconds 3 | |
| # Verify shutdown | |
| $running = wsl -l -v 2>&1 | Select-String "Running" | |
| if ($running) { | |
| Write-Host " Waiting for WSL to fully stop..." -ForegroundColor DarkYellow | |
| Start-Sleep -Seconds 5 | |
| wsl --shutdown | |
| Start-Sleep -Seconds 3 | |
| } | |
| Write-Host " WSL stopped." -ForegroundColor Gray | |
| # --- Step 5: Compact the VHDX --- | |
| Write-Host "`n[5/7] Compacting VHDX file(s)..." -ForegroundColor Yellow | |
| $hasOptimizeVHD = Get-Command Optimize-VHD -ErrorAction SilentlyContinue | |
| foreach ($vhdx in $vhdxFiles) { | |
| Write-Host " Processing: $($vhdx.FullName)" -ForegroundColor Gray | |
| if ($hasOptimizeVHD) { | |
| Write-Host " Using Optimize-VHD..." -ForegroundColor Gray | |
| Optimize-VHD -Path $vhdx.FullName -Mode Full | |
| } else { | |
| Write-Host " Optimize-VHD not available, using diskpart..." -ForegroundColor DarkYellow | |
| $diskpartScript = @" | |
| select vdisk file=""$($vhdx.FullName)"" | |
| attach vdisk readonly | |
| compact vdisk | |
| detach vdisk | |
| "@ | |
| $tempFile = [System.IO.Path]::GetTempFileName() | |
| $diskpartScript | Out-File -FilePath $tempFile -Encoding ASCII | |
| diskpart /s $tempFile | |
| Remove-Item $tempFile -Force | |
| } | |
| } | |
| Write-Host " Compaction complete." -ForegroundColor Gray | |
| # --- Step 6: Verify results --- | |
| Write-Host "`n[6/7] Verifying results..." -ForegroundColor Yellow | |
| $totalSaved = 0 | |
| foreach ($vhdx in $vhdxFiles) { | |
| # Re-read the file info after compaction | |
| $updatedFile = Get-Item $vhdx.FullName | |
| $afterGB = [math]::Round($updatedFile.Length / 1GB, 2) | |
| $beforeGB = $beforeSizes[$vhdx.FullName] | |
| $savedGB = [math]::Round($beforeGB - $afterGB, 2) | |
| $totalSaved += $savedGB | |
| Write-Host " $($vhdx.Name):" -ForegroundColor Gray | |
| Write-Host " Before: $beforeGB GB" -ForegroundColor Gray | |
| Write-Host " After: $afterGB GB" -ForegroundColor Green | |
| Write-Host " Saved: $savedGB GB" -ForegroundColor Green | |
| } | |
| if ($vhdxFiles.Count -gt 1) { | |
| Write-Host "`n Total saved: $([math]::Round($totalSaved, 2)) GB" -ForegroundColor Green | |
| } | |
| # --- Step 7: Test WSL --- | |
| Write-Host "`n[7/7] Testing WSL..." -ForegroundColor Yellow | |
| if ($Distro) { | |
| $testResult = wsl -d $Distro -- bash -c "echo 'WSL is working' && df -h / | tail -1" | |
| } else { | |
| $testResult = wsl -- bash -c "echo 'WSL is working' && df -h / | tail -1" | |
| } | |
| Write-Host " $testResult" -ForegroundColor Gray | |
| Write-Host "`n=== Complete! ===" -ForegroundColor Cyan |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment