Virtual machines tend to have a much shorter lifespan than physical machines. In fact, VMs can be created or deleted on a whim. The problem with this, however, is that when you use the Hyper-V Manager to delete a virtual machine, its virtual hard disks are not deleted, and these orphaned virtual hard disks can consume a significant amount of storage space. Microsoft presumably leaves the virtual hard disks in place as a safety measure. That way, if you want to rebuild the VM, you can use the existing virtual hard disks to do so. However, you can also end up in a situation in which your storage is cluttered by orphaned virtual hard disks. It is possible, however, to build a PowerShell script to delete and remove both virtual machines and its virtual hard disks. In this article, I will show you how it works.
Let’s get started
Before I get started, I just want to point out that in the interest of simplicity, I am going to assume that the virtual machine in question only has one virtual hard disk. It is possible to incorporate a loop into the script in a way that allows the loop to detect and remove multiple virtual hard disks, but that's another discussion for another day.
So, with that said, the first step is to find the path and file name of the virtual machine's virtual hard disk. If you enter the Get-VM cmdlet followed by the virtual machine name, you will find that the cmdlet does not display specific information about the virtual hard disk, even if you use the Select-Object cmdlet to display all of the available attributes. You can see what I mean in the image below.
As you look at the screen capture above, you will notice that it does mention hard drives, but no specific information is given. However, the fact that the information displayed to the right of the HardDrives property is shown in braces means that this is an expandable property. If you want to find the path and file name of the virtual machine's virtual hard disk, then you will need to tell PowerShell to expand this property. You can do so by using this command:
Get-VM <virtual machine name> | Select-Object -ExpandProperty HardDrives
As you can see in the next screenshot, this command returns the full path of the virtual hard disk that is being used by the virtual machine.
Now that we have managed to locate the virtual hard disk path and filename, the next step in the process is to put the path and filename into a format that we can use. This means copying it from the HardDrives property into a variable.
One way of mapping a variable to the path is to simply set the variable equal to the Get-VM cmdlet and then supply the virtual machine name followed by a couple of Select-Object commands. Here is what such a command might look like:
$A = Get-VM <virtual machine name> | Select-Object -ExpandProperty HardDrives | Select-Object Path
While this approach will work, it isn't the best option if your goal is to use the variable's contents as a tool for deleting a virtual hard disk after the corresponding VM has been removed. The reason for this is that the command that I used above stores the column header (Path) along with the path and filename, as shown below.
Thankfully, this problem is easy to solve. There are ways of accomplishing this that are more concise than what I am about to show you, but I like using this particular method because I think that it's easier to follow and less prone to errors.
The first step in the process is to map all of the attributes that are related to the virtual machine's HardDrives property to a variable. Here is what that command looks like:
$A = Get-VM <virtual machine name> | Select-Object -ExpandProperty HardDrives
When you execute this command, the $A variable will contain properties such as the virtual machine name, the controller type, the controller number, the controller location, the disk number, and the path. Now, all we have to do is to isolate the path. I like using a second variable to accomplish this. I simply reference the first variable's path attribute when assigning the second variable. Here is what the command looks like:
You can see both of these commands in the image below.
Ready to remove your virtual machines
Now that we have the necessary information about the virtual hard disk, we can move forward with removing the virtual machine. The next step in the process is to turn off the VM. Since we are deleting the VM, there is little reason to shut it down gracefully. You can stop the VM by using the Stop-VM command, followed by the virtual machine name, as shown below.
Now that the VM is stopped, the next step is to delete its virtual hard disk. To accomplish this, we can use the Remove-Item cmdlet, along with the path that we derived earlier. Assuming that you followed my example and stored the path in a variable named $B, the command looks like this:
Remove-Item -Path $B
The last step in the process is to delete the virtual machine itself. You can do this by using the Remove-VM cmdlet, followed by the virtual machine name. You can see an example below.
The virtual machine has now been deleted.
Remove virtual machines: Once done, gone forever
Although the technique that I just showed you is effective, you have to be careful using it. Virtual hard disks are typically too large for the Windows Recycle Bin, so you have to assume that anything that you delete by using this technique is gone forever.
Featured image: Shutterstock