Through the course of normal day-to-day management activities, Hyper-V virtual hard disks can sometimes become orphaned. When you delete a Hyper-V virtual machine through the Hyper-V manager, the corresponding virtual hard disk does not get deleted, and it's easy to forget to go back and remove the virtual hard disk later on. Of course, these orphaned virtual hard disks can consume a significant amount of storage space, so removing the virtual hard disks that you no longer need is a good idea.
Unfortunately, PowerShell does not have a Get-OrphanedVHD cmdlet. Therefore, you have to be a little bit creative when it comes to tracking down virtual hard disks that have been orphaned. Fortunately, there are a number of VHD-related cmdlets built into PowerShell, and you can use these cmdlets to your advantage.
It is possible to build a PowerShell script that creates an inventory of all of the virtual hard disks on the entire system, and then queries the virtual machines to see which virtual hard disks they are using. The script could then cross-reference the two lists, and remove from the list any virtual hard disks that are known to be in use, leaving you with a list of virtual hard disks.
This is certainly one way of approaching the problem. Unfortunately, I can't build such a script due to content length limitations. However, I want to show you some much easier techniques that you can use.
Windows has a built-in cmdlet called Get-VHD. This cmdlet provides information on a specified VHD file. Among the fields of information that are returned is a field called Attached. The Attached field provides you with a True or False value, as shown in the figure below.
If the Attached field displays a value of True, then the virtual hard disk is definitely not orphaned. If, on the other hand, the Attached field displays a value of False, then the virtual hard disk may or may not be orphaned. A virtual hard disk file can show an Attached value of False if it is orphaned, but it will also show a value of False if the virtual machine that is using the virtual hard disk file is powered off. If you look at the figure below, you can see that the Attached Field started out displaying a value of False, but changed to True once I started the VM.
Although the value of the Attached field can change based on the VM state, it is still a good place to begin checking to see if the virtual hard disk is orphaned, because if the value is True then you know for sure that the virtual hard disk is not orphaned.
Finding the orphan
But what if the Attached field shows a value of False? How do you know if the virtual hard disk is orphaned, or if it simply belongs to a VM that is powered off? Well, if all of your VMs are powered on, and the virtual hard disk is still showing an Attached value of False, then the virtual hard disk is probably orphaned.
Another thing that you can do is to look at the virtual hard disk's path (which is one of the attributes that is displayed by the Get-VHD cmdlet). In some cases, the Path may give clues as to which VM the virtual hard disk belongs to. In the previous figure, for example, it was pretty obvious that this virtual hard disk belongs to a VM named DOS. However, looking at the path does not always give you the information that you need.
Another thing that you can do is to search the VMs for references to the virtual hard disk. Oddly enough, the Get-VM cmdlet does not display a list of the virtual hard disks that a VM is using. Even using the Select-All cmdlet in association with the Get-VM cmdlet will not display the required information.
So the problem that we have is that the Get-VM cmdlet will list VM information, but not virtual hard disk information. Similarly, the Get-VHD cmdlet will list information about a virtual hard disk, but will not display the name of the VMs that are using the virtual hard disks. The solution to this problem is realizing that the Get-VHD cmdlet accepts pipeline input. You can't send the VM name to the Get-VHD cmdlet, but you can use the virtual machine's ID.
So with that in mind, suppose that you wanted to see the name and path of the virtual hard disk being used by a VM named DOS. To do so, you could use this command:
Get-VM DOS | Select-Object VMID | Get-VHD | Select-Object Path
You can see the output from this command in the figure below.
As helpful as this command may be, it probably isn't going to do a lot for you if you have a large number of virtual machines. Thankfully, with one really simple change, you can get a list of every virtual hard disk that is being used by VMs residing on the server. The command is as follows:
Get-VM | Select-Object VMID | Get-VHD | Select-Object Path
As you can see, I simply omitted the VM name, which effectively tells PowerShell that I want to look at every VM on the server. The end result is a list of the virtual hard disks that are being used by those VMs. You can see what this looks like in the figure below.
If you have a virtual hard disk that you suspect to be orphaned, you can cross-reference the list to see if the virtual hard disk is in use or not. As previously mentioned, it is also possible to build a script that automates the entire process and that identifies the orphaned virtual hard disks so that you do not have to look for them manually.