How To Merge Hyper-V disk and Remove Snapshot

Hyper-v can create checkpoint / Snapshot in many ways, sometime removing them can be a pain in the A… Especially if they have been created by 3rd party software. The simple way to remove snapshot is through the Hyper-v manager, just click on the VM and in the checkpoint window delete the checkpoint :

Some time the Checkpoints window is empty yet you have recovery points. and the VM disks spread on snaps. Powershell can help here :

Get-VMSnapshot -VMname "your vm name"
Get-VMSnapshot -VMname "your vm name" | Remove-VMsnapshot

When using backup software like Veeam or Acronis they backup the VM’s through the host, some time the create checkpoint but do not merge them back leaving differential disk in the format of : avhdx

In this case you need to merge the disk manually with the help of the feature “Edit Disk” in the hyper-v manager

Choose “Edit Disk” -> locate your latest avhdx disk and merge it to his parent -> in case of few you need to repeat this step until reaching the base VM disk with the vhdx file type :

If the directory is full with this kind of snapshot the manual way can be hard and long, yet I have found a nice script written by Steve Williams that merge all the disk to there parent disk one by one all the way to the end, you need to run it when the VM is off (and having a backup for the VM , because you can never know !!!) I recommend to run it with the powershell editor :


    # Written by Steve Williams, Infotect Design Solutions, 2-11-2019
    # Set the folder to search for newest file
   # FolderPath is the location of the main VHDX and AVHDX files
    $FolderPath = "Your VM Name\Virtual Hard Disks\"
   # ActiveVM is the first few letters of the VHDX name
    $ActiveVM = "IIS-Server"
    $LoopCtr = 0
   # PrefixLen is the length of ActiveVM variable (character length)
    $PrefixLen = 10

    # use Get-ChildItem to search folder. Note the Sort and Select
    $currfile1 = gci -Path $FolderPath -File | Sort-Object -Property LastWriteTime -Descending | Select Name -First 1 

    # Write to screen       
    $gofile = $currfile1.Name
    if($currfile1.Name.Substring(0,$PrefixLen) -match $ActiveVM) {

        Do {
            write-host "Running disk merge..."
            Write-host ""
            write-host "Attempting merge on" $gofile
            Write-host ""
            gci -path $FolderPath -File | Sort-Object -Property LastWriteTime -Descending | Select FullName, LastWriteTime -First 1
            Merge-VHD -Path $FolderPath\$gofile -Force
            Write-Host "Pausing for 5 seconds..."; start-sleep (5); Write-Host "Resuming..."
            $currfile1 = gci -Path $FolderPath -File | Sort-Object -Property LastWriteTime -Descending | Select Name -First 1
            $gofile = $currfile1.Name
            write-host "Loops Completed:" $LoopCtr 
        } while($currfile1.Name.Substring(0,$PrefixLen) -match $ActiveVM)
    } else {
        write-host "Stop running the script, the latest drive file is not matching."
    write-host "DONE!"

You can download a sample script from here, just change the variables :

Good Luck

Leave a Reply

Your email address will not be published. Required fields are marked *