Cleaning Hyper-V R2 unused vhd and snapshot files

cleanuphyper-v

We are using Hyper-V R2 as a platform for virtualizing development and testing environment.

After month of use, with creating / deletion of many virtual machine, the vhd store is filled with a lot of vhd and avhd files. Some of them are drives of delete virtual computers.

How can I clean up the virtual drive folder ?

Is there any command line (PowerShell?) than can enumerate all virtual computers' disk binding (so I can remove all except this list) ?

[Edit] A bit of progress

I can list all xml file for VM definitions and analyse the controller sections :

<controller0>
  <drive0>
    <pathname type="string">V:\Hyper-V\Virtual Hard Disks\my_computer_7679176A-F7AE-4D40-AC28-67FFDE7E2FEB.avhd</pathname>
    <type type="string">VHD</type>
  </drive0>
  <drive1>
    <pathname type="string">V:\Hyper-V\Virtual Hard Disks\my_computer_60892A6B-6AB4-44D7-8F08-509BF0E70A05.avhd</pathname>
    <type type="string">VHD</type>
  </drive1>
</controller0>

However, as the computer can have snapshots, it only enumerates attached disks, and not their parents disks, which are also required.

Best Answer

After some digging, I used this method :

First, get all disks of all virtual machines (my server is in french, you should replace "Disque dur" by "Hard drive" for English systems) :

$disks = Get-vm | Get-VMDisk | ? { $_.DriveName -Match "disque dur" }

Then, I extract all VHD paths :

$vhds = @()
$disks | % { Get-VHDInfo $_.DiskPath } | % { $vhds+= $_.Path }
$vhds = $vhds | select -unique
write-host $vhds.Length -Foreground Yellow

Finally, I run the following code as often as required. I stop when the length of the array stops growing :

$disks | % { Get-VHDInfo $_.DiskPath }  | select ParentPath | ? {$_.ParentPath.Length -Gt 0} | % { $vhds+= $_.ParentPath }
$vhds = $vhds | select -unique
write-host $vhds.Length -Foreground Yellow

$vhds | % { Get-VHDInfo $_ }  | select ParentPath | ? {$_.ParentPath.Length -Gt 0} | % { $vhds+= $_.ParentPath }
$vhds = $vhds | select -unique
write-host $vhds.Length -Foreground Yellow

#Repeat while Length grows

At the end, $vhds contains all used drives and their parents. Simply enumerate all .vhd and .avhd files and substract the $vhd array to find useless disks.

I know this could be rewritten in a nice script, but it solved my problem.

These cmdlets are included in Windows Server 2012, are are a separate download for previous OSes.