Skip to content

Instantly share code, notes, and snippets.

@fabianoflorentino
Created April 6, 2026 00:59
Show Gist options
  • Select an option

  • Save fabianoflorentino/87f47b86c016bff13ab4b8f7cc4f69de to your computer and use it in GitHub Desktop.

Select an option

Save fabianoflorentino/87f47b86c016bff13ab4b8f7cc4f69de to your computer and use it in GitHub Desktop.
# ===============================
# Setup log (same directory)
# ===============================
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$logFile = Join-Path $scriptDir "compact-vhdx.log"
function Log {
param ([string]$message)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$line = "[$timestamp] $message"
Write-Host $line
Add-Content -Path $logFile -Value $line
}
Log "======================================"
Log "Starting VHDX compaction"
# ===============================
# Stop WSL
# ===============================
Log "Stopping all WSL distros..."
wsl --shutdown
Start-Sleep -Seconds 5
# ===============================
# Stop Docker
# ===============================
Log "Stopping Docker Desktop..."
Stop-Process -Name "Docker Desktop" -ErrorAction SilentlyContinue
Get-Process | Where-Object {
$_.ProcessName -like "*docker*" -or $_.ProcessName -like "*com.docker*"
} | Stop-Process -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 10
# ===============================
# Wait for unlock
# ===============================
function Wait-ForFileUnlock {
param ($filePath, $timeoutSeconds = 120)
Log "Waiting for unlock: $filePath"
$elapsed = 0
while ($elapsed -lt $timeoutSeconds) {
try {
$stream = [System.IO.File]::Open($filePath, 'Open', 'ReadWrite', 'None')
$stream.Close()
Log "Unlocked: $filePath"
return $true
} catch {
Start-Sleep -Seconds 2
$elapsed += 2
}
}
Log "Timeout waiting for unlock: $filePath"
return $false
}
# ===============================
# Collect disks
# ===============================
$vhdxFiles = @()
$paths = @(
"$env:LOCALAPPDATA\Packages",
"$env:LOCALAPPDATA\wsl"
)
foreach ($path in $paths) {
if (Test-Path $path) {
$vhdxFiles += Get-ChildItem -Path $path -Recurse -Filter "*.vhdx" -ErrorAction SilentlyContinue
}
}
$dockerDisk = "$env:LOCALAPPDATA\Docker\wsl\disk\docker_data.vhdx"
if (Test-Path $dockerDisk) {
$vhdxFiles += Get-Item $dockerDisk
}
$vhdxFiles = $vhdxFiles | Sort-Object FullName -Unique
Log "--------------------------------------"
Log "Disks found:"
foreach ($disk in $vhdxFiles) {
Log $disk.FullName
}
if ($vhdxFiles.Count -eq 0) {
Log "No VHDX files found. Exiting."
exit
}
# ===============================
# Compact disks
# ===============================
foreach ($vhdx in $vhdxFiles) {
Log "--------------------------------------"
Log "Processing: $($vhdx.FullName)"
$unlocked = Wait-ForFileUnlock $vhdx.FullName
if (-not $unlocked) {
Log "Skipping (still locked): $($vhdx.FullName)"
continue
}
$diskpartScript = @"
select vdisk file="$($vhdx.FullName)"
attach vdisk readonly
compact vdisk
detach vdisk
"@
$tempFile = Join-Path $env:TEMP "diskpart_wsl.txt"
$diskpartScript | Out-File -Encoding ASCII $tempFile
Log "Compacting disk..."
# Captura saída do diskpart
$output = diskpart /s $tempFile 2>&1
foreach ($line in $output) {
Log $line
}
Remove-Item $tempFile -Force
Log "Done: $($vhdx.FullName)"
}
Log "--------------------------------------"
Log "All disks processed."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment