At times, you may find that orphaned vhdx and avhdx files are filling up your physical disk. You may have deleted the virtual machines in the Hyper-V console earlier, but their disks were never cleaned up. The script below lists all vhdx and avhdx files in a certain location and checks in Hyper-V if they appear in the configuration of any of the VMs. If none of the files in a certain folder are listed as found it’s a strong indication that they are no longer needed. You should check the last write time in addition.
Mind that it is not the purpose of the script to check if any avhdx files (differencing files created by Checkpoints) are obsolete but to determine if the vhdx and any avhdx files can be removed.
Also, before deleting anything, be sure to validate the result of the script. Better move the disks to a temporary location first, make yourself a note of the source folder and check if all VMs are still working before the final deletion. A backup will give you additional certainty that you don’t lose any machines that are still required.
Based on the output of the script, here’s an example of files that can be deleted:
If you look at the files in the folder E:\MachineRoom\TP2001, you see that none of them has been found in any Hyper-V configuration. An example of a VM that is still active is MAX8014 located in E:\MachineRoom\MAX8014: As you see E:\MachineRoom\MAX8014\MAX8014\Virtual Hard Disks\MAX8014_ED13FC88-69B1-4A16-862F-70CFC0BEEEC4.avhdx has been found. If you check the machine in Hyper-V, it confirms the result, thus don’t touch any files in E:\MachineRoom\MAX8014.
#Hyper-V VM CleanUp helper
#V1.0, Nov. 2022
#This script is provided "AS-IS" with no warrenties
$vhdxLocation = 'E:\MachineRoom'
$vhdxs = Get-VM -VMName * | Select-Object VMId | Get-VHD
#Get files on disk. Filter alloes search for vhdx and avhdx
$vhdxsOnDisk = Get-ChildItem -Path $vhdxLocation -Filter *.*vhdx -Recurse -ErrorAction SilentlyContinue -Force
foreach ($vhdxod in $vhdxsOnDisk){
$PathOnDisk = ([string]$vhdxod.Directory + '\' + $vhdxod.Name)
$LastWriteTime = $vhdxod.LastWriteTime.ToString("yyyy-MM-dd")
$Size = ([string] $vhdxod.Length/(1024*1024))
$found = $false
foreach($vhdx in $vhdxs){
#Write-Host $vhdx.Path -BackgroundColor DarkBlue -ForegroundColor yellow
if($vhdx.Path -eq $PathOnDisk)
{
#Write-Host $vhdxod.Directory -BackgroundColor DarkGreen -ForegroundColor White
$found = $true
break
}
else
{
#Write-Host $vhdxod.Directory -BackgroundColor DarkYellow -ForegroundColor White
$found = $false
}
}
if($found)
{
Write-Host ('Found: ' + $PathOnDisk + ' Last write time: ' + $LastWriteTime + ' SizeInMB: ' + $Size) -BackgroundColor Green -ForegroundColor Black
}
else
{
Write-Host ("Not found: " +$PathOnDisk + ' Last write time: ' + $LastWriteTime + ' SizeInMB: ' + $Size) -BackgroundColor Yellow -ForegroundColor Blue
}
}
Links:
What is the proper way to cleanup excess .avhdx files created by Hyper-V?
Use PowerShell to Explore Old Windows VHDs
https://devblogs.microsoft.com/scripting/use-powershell-to-explore-old-windows-vhds/