Use PowerShell 3.0 to Optimize Hyper-V VHD Size

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell 3.0 to optimize Hyper-V VHD disk size.

Microsoft Scripting Guy, Ed Wilson, is here. One of my favorite Windows 8 features is that (depending on the age of your laptop) you can add real-live, honest-to-goodness Hyper-V. This is such a cool feature because Microsoft Hyper-V technology is awesome. To be able to run it on a laptop with Windows 8 is also awesome. What is even better is that Windows 8 and Windows Server 2012 include an extremely well thought out Hyper-V module for use from within Windows PowerShell 3.0. It absolutely rocks.

It seems that with every cool thing, there is always a tradeoff. In my case, it is disk space. I have one laptop that is capable of running Windows 8 and Hyper-V, and unfortunately, it has a really small hard disk drive. Even after turning off hibernation support (and thereby reclaiming 8 GB of disk space), shrinking my page file, and forming extreme disk cleanup, my laptop is still sucking fumes when it comes to being able to do things like create Word documents or take screenshots.

Another bad thing is that with the Hyper-V module, it is really easy to create VHDs. This also offers a bit of respite.

I keep all of my virtual machines in a folder off the root of my drive C, which is named VMs. To find the size of all of my virtual machines, I use the Get-ChildItem cmdlet, and I use a variable to add the length of all of the files. This command is shown here (gci is an alias for the Get-ChildItem cmdlet. The % sign is an alias for the Foreach-Object cmdlet).  

PS C:\> gci -File -Filter *.vhd* -Path C:\VMs -Recurse | % {$l += $_.length}

I now look at the number that is stored in the $l variable. The result is shown here.

PS C:\> $l


A great big number with no commas in it is a bit hard to read. I decide to convert the number to gigabytes as shown here.

PS C:\> $l / 1gb


It appears that I have over 50 and a half gigabytes of virtual hard disks on my rather small laptop drive. No wonder I am sucking fumes when I attempt to create a new Word document or any other such a thing. I can optimize all of these virtual machine disks and reclaim a bit of disk space. To do this, I use the first command that finds all of the VHDs and pipe it to the Optimize-VHD cmdlet.

The Optimize-VHD cmdlet will perform multiple types of optimization—but for now, I am going to do a quick optimization. On my laptop, it completes in a couple of minutes (but I do have a fast processor, a lot of memory, and an SSD). As the optimization progresses, a Windows PowerShell progress bar appears in the Windows PowerShell console, as shown here.

Image of command output

The error that presents itself under the progress bar says that Optimize-VHD is unable to compact the disk of that particular type. This occurs because one of my VHDs is a fixed disk VHD (not a VHDX) format. It is a small 1-gigabyte disk that I use to permit easy transfer of data between different virtual machines. I attach and detach this virtual hard disk at will. It is a pretty cool idea that I came up with a while back, which helps overcome the problem of not having immediate access to system hard drives. In fact, I could use the VHD to store items I need from the host operating system because, as I talked about in Use PowerShell to Mount ISO Files in Windows 8, I can easily mount a VHD from within Windows 8 and Windows Server 2012.

I now decide to check the amount of disk space that is consumed by the VHD* drives. I need to initialize the $i counter variable that I use, and then I run the same commands as previously by stepping through my command buffer. Here are the commands and the results.

PS C:\> $l=$null

PS C:\> gci -File -Filter *.vhd* -Path C:\VMs -Recurse | % {$l += $_.length}

PS C:\> $l


PS C:\> $l / 1gb


I now see that I saved a half gig of disk space. Not bad for only a couple minutes of work.

Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy