Skip to content
cyharyantoPublic

About

Collections of my WSL tools for various issues.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wsl-tools

A small PowerShell module for inspecting and maintaining WSL2 distros from the Windows host.

Warning

Optimize-WslVhdx operates on the live ext4.vhdx files that hold your WSL distro filesystems. Always back up important data inside your distros before running it — at minimum copy your home directory, project repos, and any databases out, or use wsl --export to snapshot a full distro to a tarball.

Caution

This software is provided "AS IS", without warranty of any kind, express or implied (see LICENSE). Tools that touch virtual disks can in rare cases corrupt them. You are solely responsible for any data loss or system damage. Read what each cmdlet does before running it; understand the steps; and keep backups.

Cmdlets

Cmdlet What it does
Get-WslDistro List installed distros with their state and vhdx paths.
Get-WslDiskUsage Report each distro's vhdx size on the host plus a best-effort reclaimable estimate from inside the distro.
Optimize-WslVhdx Reclaim space from a grown ext4.vhdx via diskpart. Self-elevates (UAC).
Get-MsStoreAutoUpdate Report whether Microsoft Store background auto-updates are off (policy + scan tasks). Read-only, no admin.
Disable-MsStoreAutoUpdate Stop Store from auto-updating WSL (and other Store apps) in the background. Self-elevates (UAC).
Enable-MsStoreAutoUpdate Reverse of Disable-MsStoreAutoUpdate. Self-elevates (UAC).

Requirements

  • Windows 10 / 11 with WSL2
  • Windows PowerShell 5.1 or PowerShell 7+
  • Administrator rights for Optimize-WslVhdx (it will prompt via UAC)
  • Pester 5+ for tests (optional)

Installation

git clone https://github.com/cyharyanto/wsl-tools.git
Import-Module .\wsl-tools\WslTools

Usage

Get-WslDistro
Get-WslDiskUsage             # default: best-effort inside-distro probe
Get-WslDiskUsage -HostOnly   # skip inside probe (faster, no distro startup)
Optimize-WslVhdx -Distribution Ubuntu -Verbose

See examples/ for runnable scripts.

Example: reclaiming 90 GB from an Ubuntu WSL2 distro

A common scenario: your Windows C: drive is filling up and you can't see where the space went. WSL2 stores each distro's filesystem in an ext4.vhdx file that grows as you write data but never shrinks on its own — even after you delete files inside the distro or run fstrim. After a year of development work, an Ubuntu vhdx can easily balloon to 200 GB on the host while only ~100 GB is actually used inside.

1. Find which distro is hogging disk space

PS> Get-WslDiskUsage | Sort-Object VhdxSizeBytes -Descending

Name             State           Size   UsedInside  Reclaimable VhdxPath
----             -----           ----   ----------  ----------- --------
Ubuntu           Stopped     205.25 GB   115.00 GB     90.25 GB C:\Users\you\AppData\Local\Packages\CanonicalGroupLim...\ext4.vhdx
Debian           Stopped      26.38 GB     8.20 GB     18.18 GB C:\Users\you\AppData\Local\wsl\{...}\ext4.vhdx
archlinux        Stopped      11.44 GB     6.10 GB      5.34 GB C:\Users\you\AppData\Local\wsl\{...}\ext4.vhdx
docker-desktop   Stopped     112.00 MB                          C:\Users\you\AppData\Local\Docker\wsl\main\ext4.vhdx

The Ubuntu vhdx has roughly 90 GB of empty space inside it that is invisible to Windows. Reclaim it by compacting the vhdx.

2. Compact the vhdx

Important

Quit Docker Desktop fully from the system tray before running Optimize-WslVhdx. While Docker Desktop is running, wsl --shutdown is effectively a no-op because Docker keeps the WSL2 utility VM alive, and the compact will fail with file is being used by another process.

PS> Optimize-WslVhdx -Distribution Ubuntu -RunFstrim -Verbose

Distribution    : Ubuntu
VhdxPath        : C:\Users\you\AppData\Local\Packages\CanonicalGroupLim...\ext4.vhdx
SizeBeforeBytes : 220336553984
SizeAfterBytes  : 148771672064
SizeBeforeGB    : 205.25
SizeAfterGB     : 138.57
ReclaimedGB     : 66.68

What happened, end-to-end:

  1. sudo fstrim -av ran inside Ubuntu to mark unused blocks free.
  2. wsl --shutdown released the vhdx handle on the Windows side.
  3. The cmdlet self-elevated via UAC and ran diskpart compact vdisk against the file.
  4. The Ubuntu vhdx shrank from 205.25 GB to 138.57 GB, freeing about 67 GB on the C: drive.

For "find the distro with the most reclaimable space and compact it" in one shot, see examples/Optimize-LargestDistro.ps1.

Stopping Microsoft Store from auto-upgrading WSL in the background

WSL itself ships as a Microsoft Store Appx package (MicrosoftCorporationII.WindowsSubsystemForLinux). Store updates the package in the background on its own schedule. If your Docker Desktop / running distros happen to be using C:\Program Files\WSL\* when Store fires, the MSI step of the upgrade can fail with:

MsiInstaller 11922 (Error) Error 1922. Service 'WSL Service' (WSLService) could not be deleted.
MsiInstaller 11708        Installation failed.

When that happens the WSL utility VM is restarted mid-failure, all your running distros (including Docker Desktop's docker-desktop distro) drop, and Docker bounces. Store then keeps retrying the same failing upgrade every few hours.

On Windows 11 build 26200 (Canary) and similar recent builds, the Microsoft Store UI no longer exposes a permanent "App updates off" toggle — only Pause 1–5 weeks. The two layers underneath that gate Store auto-updates still work though:

Layer Mechanism
Policy HKLM\SOFTWARE\Policies\Microsoft\WindowsStore!AutoDownload = 2 — Store may notify, may not auto-install.
Background scan \Microsoft\Windows\InstallService\ScanForUpdates and ScanForUpdatesAsUser scheduled tasks disabled — Store does not even check in the background.

Apply both with one command:

Disable-MsStoreAutoUpdate

Reverse with Enable-MsStoreAutoUpdate. Check current state with Get-MsStoreAutoUpdate. Manual updates via Store → Library → Get updates still work — that path starts InstallService on demand and applies updates you explicitly choose. Run it right after a fresh Windows reboot when nothing holds WSL files open, and the install completes in seconds.

PS> Get-MsStoreAutoUpdate

Effective            : Disabled
AutoDownloadPolicy   : Disabled
AutoDownloadValue    : 2
ScanForUpdates       : Disabled
ScanForUpdatesAsUser : Disabled

Note

On Canary/Insider builds Microsoft occasionally re-enables Store policies as part of telemetry. Re-run Get-MsStoreAutoUpdate after a cumulative update; rerun Disable-MsStoreAutoUpdate if anything came back.

Compacting: known gotcha

If Docker Desktop is running, the WSL VM auto-restarts within seconds of wsl --shutdown — Docker Desktop holds the VM up and keeps vhdx file handles open. The diskpart compact then fails with file is being used by another process. Quit Docker Desktop fully (tray icon -> Quit) before calling Optimize-WslVhdx. The cmdlet pre-flights this and aborts with a clear message; pass -Force to override.

Notes on the docker-desktop distro

Docker Desktop registers a docker-desktop WSL distro whose registry path points at a small system vhdx (~100 MB). Docker stores its actual data in a separate docker_data.vhdx outside the standard WSL layout. This module reports only what the WSL registry exposes; manage Docker Desktop storage through Docker's own settings ("Resources -> Disk image size" / "Clean / Purge data").

Execution policy

By default, Windows blocks unsigned PowerShell modules under AllSigned policy. To use this module on your machine, allow local scripts for your user:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

Or run a one-off session with -ExecutionPolicy Bypass.

Tests

Invoke-Pester ./tests                          # unit tests, mocked, fast
Invoke-Pester ./tests -TagFilter Integration   # real-WSL tests, opt-in

License

MIT — see LICENSE.

About

Collections of my WSL tools for various issues.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages