I recently received an email from someone who attended one of my presentations asking if I had a blog article on using PowerShell to compact and optimize VHD files. Since I didn’t have a blog article on that subject, I decided to create one.
The process itself is fairly simple. The examples shown in this blog article are being run on a Windows 10 computer which has Hyper-V enabled on it. Only specific SKU’s of Windows 10 are capable of running Hyper-V. The same process can be used on servers running Windows Server 2012 R2 or Windows Server 2016 (and possibly on other versions, but I can’t confirm that).
There are several PowerShell cmdlets for working with VHD files as shown in the following example.
Get-Command -Noun VHD* -Module Hyper-V
The Convert-VHD cmdlet can be used to change the format (VHD to VHDX or vise-versa), Type (fixed, dynamic, and differencing), and block size of the file.
The following example converts a VHD file to a VHDX file.
Convert-VHD -Path 'D:\Hyper-V\Virtual Hard Disks\nano2.vhd' -DestinationPath 'D:\Hyper-V\Virtual Hard Disks\nano2.vhdx'
There are a number of parameters for the Convert-VHD cmdlet so be sure to take a look at the help for it. The BlockSizeBytes parameter is used to change the block size, the DeleteSource parameter is used to delete the source file once the destination file is created, and the VHDType parameter is used to change the type of VHD (fixed, dynamic, or differencing).
One thing to keep in mind is the conversion process is an offline operation. The help states that the file being converted can’t be attached, but what I’ve found is that it can be attached as long as the VM (virtual machine) isn’t running.
The Optimize-VHD cmdlet is used to optimize the amount of space used by dynamic virtual hard drive files. When this cmdlet is run, it compacts the virtual file as shown in the following example.
Optimize-VHD -Path 'D:\Hyper-V\Virtual Hard Disks\srv1e.vhd'
Based on the information found in the help, this cmdlet not only reclaims unused blocks, but it also rearranges the blocks to be more efficiently packed, which also reduces the size of the VHD or VHDX. It’s possible for this command to complete without shrinking the virtual file if no optimization is necessary. The Mode parameter can be used to change the default mode which is Full for VHD files and Quick for VHDX files.
The Resize-VHD cmdlet is used to shrink VHDX files or expand both VHD and VHDX files. The shrink operation will fail if a size smaller than the minimum size is specified as shown in the following example.
Get-VHD -Path 'D:\Hyper-V\Virtual Hard Disks\srv1e.vhd'
The MinimumSize parameter can be used to shrink a VHDX to it’s minimum size without having to worry about the possibility of specifying a file size that’s too small.
Resize-VHD -Path 'D:\Hyper-V\Virtual Hard Disks\srv1.vhdx' -ToMinimumSize
Be sure to take a look at the help for the Resize-VHD cmdlet to determine all of the available options.