Use PowerShell to Determine the Chain of VHD’s for a Virtual Machine on Hyper-V

You want to determine what VHD's exist for the virtual machines (VM's) that are virtualized on your Windows 8 or Windows Server 2012 Hyper-V virtualization host.

This may sound simple, but what if you have a base image or template that has been configured and then multiple VM's have been created using differencing disks that reference that single base image? If that weren't difficult enough to keep track of, you may also have snapshots of those VM's which are also classified as differencing disks in HyperV.

How do you easily figure out what the chain is for all of the VHD's or VHDX files that are necessary for a virtual machine? I couldn't find a way to determine this easily so I decided to write a PowerShell function to figure this out.

I recently added a second hard drive (an SSD) to my laptop computer and I want to move some of the virtual hard drive files to this drive.

 1#Requires -Version 3.0
 2#Requires -Modules Hyper-V
 3function Get-VHDChain {
 4
 5    [CmdletBinding()]
 6    param(
 7        [string]$ComputerName = $env:COMPUTERNAME,
 8        [string[]]$Name = '*'
 9    )
10
11    try {
12        $VMs = Get-VM -ComputerName $ComputerName -Name $Name -ErrorAction Stop
13    }
14    catch {
15        Write-Warning $_.Exception.Message
16    }
17
18    foreach ($vm in $VMs){
19        $VHDs = ($vm).harddrives.path
20
21        foreach ($vhd in $VHDs){
22            Clear-Variable VHDType -ErrorAction SilentlyContinue
23
24            try {
25                $VHDInfo = $vhd | Get-VHD -ComputerName $ComputerName -ErrorAction Stop
26            }
27            catch {
28                $VHDType = 'Error'
29                $VHDPath = $vhd
30                Write-Verbose $_.Exception.Message
31            }
32
33            $i = 1
34            $problem = $false
35
36            while (($VHDInfo.parentpath -or $i -eq 1) -and (-not($problem))){
37                If ($VHDType -ne 'Error' -and $i -gt 1){
38                    try {
39                        $VHDInfo = $VHDInfo.ParentPath | Get-VHD -ComputerName $ComputerName -ErrorAction Stop
40                    }
41                    catch {
42                        $VHDType = 'Error'
43                        $VHDPath = $VHDInfo.parentpath
44                        Write-Verbose $_.Exception.Message
45                    }
46                }
47
48                if ($VHDType -ne 'Error'){
49                    $VHDType = $VHDInfo.VhdType
50                    $VHDPath = $VHDInfo.path
51                }
52                else {
53                    $problem = $true
54                }
55
56                [pscustomobject]@{
57                    Name = $vm.name
58                    VHDNumber = $i
59                    VHDType = $VHDType
60                    VHD = $VHDPath
61                }
62
63                $i++
64            }
65        }
66    }
67}

I've already moved a couple of the VHDX files as you can see in the results where the VHDType is "Error":

vhdchain-1.png

µ