Compact Docker Desktop's VHDX safely on Windows with PowerShell automation.
Reclaim disk space by compacting Docker Desktop's docker_data.vhdx safely through zero-filling free space inside the Docker WSL distro and then running a host-side compaction. This script does not install any distro — it uses Docker Desktop's built-in docker-desktop WSL distro.
- What it does
- Requirements
- Installation
- Usage
- Examples
- How incremental mode works
- Safety & Notes
- Troubleshooting
- Changelog
- License
- Validates the environment (WSL installed, Docker distro exists, VHDX accessible) and checks host drive free space
- Analyzes potential space savings before running (estimates reclaimable GB)
- Optionally simulates the plan (
-WhatIf) or prompts for confirmation (unless-Force) - Zero-fills free space inside the Docker data disk using incremental cycles (write N GB at a time) or a single full zero-fill
- Shuts down WSL so the VHDX is not in use
- Compacts the VHDX using
Optimize-VHD(Hyper-V module) if available, otherwise falls back todiskpart compact vdisk - Displays comprehensive progress with real-time updates, elapsed time tracking, and final summary statistics
- Windows with PowerShell 5.1 or later
- Docker Desktop with WSL2 backend (includes the
docker-desktopdistro by default) - Sufficient host free disk space for temporary VHDX growth during zero-filling
- Incremental mode available to limit peak space usage
- Optional: Hyper-V PowerShell module for
Optimize-VHD(recommended but not required —diskpartis used as fallback)
Admin privileges: The script automatically elevates itself when needed (except in -WhatIf simulation mode)
-
Download or save the script as
Shrink-DockerDataVHDX.ps1 -
No need to "Run as Administrator" — the script will automatically elevate itself when needed
-
If your execution policy prevents running scripts, use:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserOr run with bypass:
powershell -ExecutionPolicy Bypass -File .\Shrink-DockerDataVHDX.ps1Note: When the script needs admin privileges, Windows will show a UAC prompt asking for permission to elevate.
.\Shrink-DockerDataVHDX.ps1 [-Mode <Interactive|Incremental|Full|Auto>] [-MinFreeSpaceGB <int>]
[-VhdxRelativePath <string>] [-Force] [-WhatIf]
[-MaxIncrementalSizeGB <int>] [-MaxCycles <int>]| Parameter | Type | Default | Description |
|---|---|---|---|
-Mode |
string | Interactive |
Operation mode: Interactive (Menu), Incremental, Full, or Auto. |
-MinFreeSpaceGB |
int | 20 |
Minimum free space (GB) required on host drive before proceeding |
-VhdxRelativePath |
string | Docker\wsl\disk\docker_data.vhdx |
Path relative to %LOCALAPPDATA% |
-Force |
switch | - | Skip interactive prompts (confirmation & elevation). Fails if not Admin. |
-WhatIf |
switch | - | Simulation mode — show plan without making changes (no admin required) |
-MaxIncrementalSizeGB |
int | 0 |
If > 0, write N GB per cycle and compact between cycles |
-MaxCycles |
int | 10 |
Maximum cycles to run in incremental mode |
.\Shrink-DockerDataVHDX.ps1 -WhatIfOutput example:
[WhatIf] Plan summary:
VHDX: C:\Users\YourName\AppData\Local\Docker\wsl\disk\docker_data.vhdx
Host drive free: 45.23 GB
MinFreeSpaceGB: 20
Full-mode: write filler until disk full inside docker-desktop, then shutdown and compact
Force: no
[SIMULATION] Starting simulated execution...
[SIM] Cycle 1 of 1 - Writing 25 GB (full mode)...
[SIM] ✓ Compaction complete (simulated)
========================================
COMPACTION COMPLETE (SIMULATED)
========================================
Initial VHDX size: 85.3 GB
Final VHDX size: 85.3 GB (simulated)
Space saved: 0 GB (0%) - simulation only
========================================
This is a simulation only; no actions were executed.
.\Shrink-DockerDataVHDX.ps1The script will analyze system conditions, show the recommended mode, then display a menu:
[Auto-Select] Analyzing system conditions...
Free space: 45 GB
Minimum required: 20 GB
VHDX size: 60 GB
[Auto-Select] → FULL MODE (Plenty of disk space - faster approach)
Choose an option:
1) Simulate Full mode
2) Simulate Incremental mode
3) Run Full mode (danger zone - requires admin)
4) Run Incremental mode (safer - requires admin)
5) Exit
Type 'YES' to proceed, anything else to abort:
.\Shrink-DockerDataVHDX.ps1 -Mode Full -Force.\Shrink-DockerDataVHDX.ps1 -Mode Incremental -MaxIncrementalSizeGB 10 -MaxCycles 5 -ForceBest for: Systems with limited free space or when you want more control over the process.
.\Shrink-DockerDataVHDX.ps1 -Mode Auto -WhatIfAuto mode intelligently selects:
- Full mode when you have plenty of disk space (> 2x MinFreeSpaceGB and > 50 GB free)
- Incremental mode when disk space is limited or VHDX is very large
Output example:
[Auto-Select] Analyzing system conditions...
Free space: 7 GB
Minimum required: 20 GB
VHDX size: 60 GB
[Auto-Select] → **INCREMENTAL MODE** (Limited disk space - safer approach)
Reason: Free space ratio (0.35) indicates tight disk space
.\Shrink-DockerDataVHDX.ps1 -VhdxRelativePath "CustomPath\docker.vhdx" -MinFreeSpaceGB 10Incremental mode helps avoid large temporary spikes in host disk usage. Each cycle:
- Measures host free space and ensures at least
MinFreeSpaceGBremains - Writes a zero-filled file of N GB inside
/mnt/docker-desktop-disk/zero.fill(indocker-desktopdistro) - Syncs and removes the filler file
- Shuts down WSL with
wsl --shutdown - Compacts the VHDX using Optimize-VHD or diskpart
- Re-measures host free space and repeats until
MaxCyclesreached or insufficient headroom
Progress tracking: Each cycle displays elapsed time, space saved, and overall progress (e.g., "Cycle 3 (max 5)"). Note: Shows "(max N)" because actual cycles may be fewer based on available disk space.
┌─────────────────────────────────────────────────────────────�
│ Cycle 1: Write 10GB → Compact → Reclaim space │
│ Cycle 2: Write 10GB → Compact → Reclaim space │
│ Cycle 3: Write 10GB → Compact → Reclaim space │
│ ... │
└─────────────────────────────────────────────────────────────┘
The script provides comprehensive progress feedback:
- PowerShell progress bars showing current operation and elapsed time
- Real-time VHDX size monitoring during compaction (when using Optimize-VHD)
- Per-cycle statistics in incremental mode (space saved, time taken)
- Periodic console updates so you know the script is still working
- Final summary report showing:
- Initial vs final VHDX size
- Total space saved (GB and percentage)
- Operation completion time
Example output:
========================================
COMPACTION COMPLETE
========================================
Initial VHDX size: 85.3 GB
Final VHDX size: 52.1 GB
Space saved: 33.2 GB (38.9%)
========================================
-
⚠️ Interruption risks: DO NOT KILL the script during VHDX compaction (Optimize-VHD or diskpart operations). Killing during this phase can corrupt the VHDX and make Docker unusable. Zero-fill phase is safer to interrupt if absolutely necessary. -
🐳 Docker Desktop Protection: The script actively monitors for Docker Desktop:
- Pre-execution: Blocks if Docker Desktop is running (requires exclusive VHDX access)
- During compaction: Monitors every 3-5 seconds for Docker starting
- Critical protection: Immediately stops compaction if Docker starts to prevent corruption
- Auto-close: Can force-close Docker Desktop (interactive mode waits for manual close)
-
🔐 Self-elevation: Script automatically requests admin privileges when needed via UAC prompt
-
💾 Host disk space: Zero-filling temporarily expands the VHDX. Ensure sufficient free space or use incremental mode
-
🔒 Backup first: Always backup important data before manipulating VHDX files
-
âš¡ Optimize-VHD vs diskpart:
Optimize-VHD(Hyper-V module) is faster and preferred;diskpartis used as automatic fallback -
� Minimal environment: The
docker-desktopdistro is minimal — the script only writes to/mnt/docker-desktop-disk, no package installation needed -
ðŸ"Š Space monitoring: Script checks host free space and aborts if below
-MinFreeSpaceGB -
ðŸ›' Docker Desktop impact: Docker Desktop will be stopped during the process (WSL shutdown required for compaction)
-
ðŸ🤖 Auto-configuration: When free space is limited (< 10 GB), the script automatically adjusts parameters for safety:
- Reduces
MinFreeSpaceGBto 3-5 GB - Reduces
MaxIncrementalSizeGBto 2 GB - Warns about tight disk space conditions
- Reduces
Cause: Docker Desktop not installed or VHDX at non-default location
Solution: Verify Docker Desktop installation. Check VHDX location at %LOCALAPPDATA%\Docker\wsl\disk\docker_data.vhdx or specify custom path with -VhdxRelativePath
Cause: Self-elevation failed or was cancelled
Solution:
- If you cancelled the UAC prompt, run the script again and approve the elevation request
- Alternatively, manually run PowerShell as Administrator before running the script
- Note:
-WhatIfsimulation mode doesn't require admin privileges
Status: Not an error — the script automatically uses diskpart fallback
To enable Optimize-VHD: Install Hyper-V PowerShell module:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-Management-PowerShellCause: Process locking the VHDX (WSL still running or Docker Desktop active)
Solution: Ensure WSL is stopped. The script calls wsl --shutdown automatically, but verify with:
wsl --list --runningCause: Insufficient free space for full zero-fill operation
Solution:
- Stop script immediately (Ctrl+C)
- Use smaller
-MaxIncrementalSizeGBvalue (e.g., 5 or 10 GB) - Increase
-MinFreeSpaceGBthreshold for more safety margin - Move VHDX to larger drive (requires Docker Desktop reconfiguration)
Cause: Normal behavior — zero-filling large amounts of space takes time
Expected duration: Can take 15-60+ minutes depending on disk size and speed
Monitor: The script shows progress bars and periodic status updates. If you see the progress bar and elapsed time updating, the script is working correctly.
Q: Do I need to run PowerShell as Administrator?
A: No! The script automatically elevates itself when needed. Just double-click or run normally, and approve the UAC prompt when it appears.
Q: How much space can I reclaim?
A: Depends on how much unused space is in your Docker containers/images. Typical savings: 10-50% of current VHDX size.
Q: Will this delete my Docker images/containers?
A: No, this only compacts free space. Your Docker data remains intact.
Q: How long does it take?
A: Typically 15-60 minutes depending on VHDX size and disk speed. Incremental mode is slower but safer.
Q: Can I run this on a schedule?
A: Yes, use Windows Task Scheduler with the -Force parameter for automated runs. Configure the task to run with highest privileges.
Q: Does this work with Docker Desktop using Hyper-V backend?
A: This script is designed for WSL2 backend. Hyper-V backend uses different VHDX locations.
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project includes automated checks to ensure code quality and safety.
- Static Analysis: Run the included helper script to check for syntax errors and best practices.
.\Run-PSScriptAnalyzer.ps1 - Simulation: Always run with
-WhatIfbefore committing changes..\Shrink-DockerDataVHDX.ps1 -WhatIf
- Manual Checklist: Refer to
TEST_CHECKLIST.mdfor a step-by-step guide to manually validating the script.
A GitHub Actions workflow (.github/workflows/ps1-test.yml) automatically runs on every push and pull request to ensure code quality and functionality:
-
PSScriptAnalyzer Linting
- Scans for Errors, Warnings, and Information level issues
- Fails build on Error severity issues
- Reports all findings for quality tracking
-
Syntax Validation
- Verifies PowerShell syntax is valid
- Prevents broken scripts from being merged
-
Functional Testing
- Executes
-WhatIfsimulation to ensure script runs without crashing - Tests multiple parameter combinations:
- Custom MinFreeSpaceGB values
- Incremental mode with different cycle sizes
- Force flag behavior
- Auto mode with system analysis
- Executes
-
Code Quality Checks
- Scans for TODO/FIXME/HACK comments
- Reports technical debt for tracking
- Push to
mainbranch - Pull request against
mainbranch - Manual trigger via GitHub Actions UI
See CHANGELOG.md for the full version history and release notes.
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by the need to manage Docker Desktop's disk usage on Windows
- Uses standard Windows tools (WSL, diskpart, Optimize-VHD) for maximum compatibility
Made with �� for Docker Desktop users fighting disk space issues