How to Compact Hyper-V Windows VHD Disk File

Note that this instruction is for Windows VMs (not Linux).

It works for VHD and VHDx files as long as they use dynamic size (not fixed).

TL;DR

Shut down the Hyper-V VM.

Mount VHD as a drive in Windows (e.g. F:).

Run the following sequence as an Administrator (change F: to your drive).

defrag F: /H /X
defrag F: /H /K /L
defrag F: /H /X
defrag F: /H /K /L

Unmount VHD drive in Windows.

Use Hyper-V Manager to Compact Drive (Settings -> Hard Drive -> Edit -> Compact).

Hyper-V

Slightly longer read

If you open Hyper-V Manager, go to VM settings and open VM Hard Drive, there are Inspect and Edit buttons.

Hyper-V Manager VM Settings

Click 'Inspect' to see how much space your virtual hard drive takes.

Inspect VHD 20GB

Click 'Edit', and eventually, you will get to the 'Compact' option.

VHD Disk Settings Compact

Once the disk is compacted, the disk space savings are usually not that great.

Inspect VHD 18GB

The compact option simply trims the empty space at the end of the disk, and if data on the disk is spread all over the space, there is not much to trim.

To improve things, you need to defragment the disk, so the data takes continuous space at the beginning.

Open Windows Explorer and mount the VHD drive.

Mount VHD Drive in Windows Explorer

In this case, VHD has been mounted as F: drive.

VHD Mounted as F: Drive

Open Command Line as an Administrator and type the defragmentation incantation. Replace the 'F:' with your drive letter.

defrag F: /H /X
defrag F: /H /K /L
defrag F: /H /X
defrag F: /H /K /L

The first line defragments the disk; the second line consolidates free space at the end of the disk.

Then the process is repeated, as I've noticed that repeating it results in extra free space (500MB in this case).

Now you can unmount the F: drive and compact it again. The final result is 8GB of space reclaimed.

Inspect VHD 12GB

Command line

You can use diskpart command line tool (as an Administrator) to attach, detach and compact disks.

diskpart

DISKPART> select vdisk file="C:\Hyper-V\Virtual Hard Disks\Windows 11.vhdx"
DISKPART> attach vdisk

*** At this point, open new command-line window and run defrag commands ***

DISKPART> detach vdisk
DISKPART> compact vdisk
DISKPART> exit

PowerShell

Make sure that you have Hyper-V Module for Windows PowerShell installed.

Hyper-V PowerShell Module Feature.png

Run the following PowerShell commands as an Administrator.

$vhdFile = "C:\Temp\VHDTest\Windows 11.vhdx"
Mount-VHD $vhdFile
defrag F: /H /X
defrag F: /H /K /L
defrag F: /H /X
defrag F: /H /K /L
Dismount-VHD $vhdFile
Optimize-VHD $vhdFile