Powershell script to merge VM disks

In some situations you might find a VM disk to be part of a series of differencing disks. Take this example:If this was the result of VM Checkpoints, the fix would be easy: simply delete the checkpoints which merges the disks. But his is not the case. Hyper-V Manager shows no che

5 Star
2,695 times
Add to favorites
E-mail Twitter del.icio.us Digg Facebook
Sign in to ask a question

  • Cont to prev question
    1 Posts | Last post April 09, 2019
    • function Merge-VMDisks{
                  [String]$ComputerName = "."
          Write-Verbose "Getting disk information for file '$VHDPath' on computer '$ComputerName'"
          try {
              $VHDSVC = Get-WmiObject -ComputerName $ComputerName -Namespace root\virtualization\v2 -Class Msvm_ImageManagementService -ErrorAction Stop
              $VHDInfo = [xml]$VHDSVC.GetVirtualHardDiskSettingData($VHDPath).SettingData
              if ($VHDInfo) {
                  $ParentPath = ($VHDInfo.INSTANCE.PROPERTY | Where { $_.Name -eq "ParentPath" }).Value
                  $Result = $VHDPath,$ParentPath
                  While ($ParentPath.Split(".")[1] -match "avhd") {
                      $VHDInfo = [xml]$VHDSVC.GetVirtualHardDiskSettingData($ParentPath).SettingData
                      $ParentPath = ($VHDInfo.INSTANCE.PROPERTY | Where { $_.Name -eq "ParentPath" }).Value
                      $Result += $ParentPath
              } else {
                  Write-Warning "Disk file '$VHDPath' does not exist on computer '$ComputerName'" 
          } catch {
              Write-Warning "Computer '$ComputerName' is offline or cannot be contacted" 
  • Incredible, new to power-shell scripting
    1 Posts | Last post April 09, 2019
    • Hi Sam, 
      After reading the code and from my understanding the code has 2 separated functions. 
      (Get-ParentPath) for finding the parent file and bring a list of avhdx files that have to be merged. 
      And (Merge-VMDisks) function doing the merge task? Am I in the right path? 
      I have loaded the 
      (Get-ParentPath) function as following:
      function Get-ParentPath {
        $VMName = "my computer name"
        $HVName = "my host name"
        $VMDisks = Invoke-Command -ComputerName $HVName -ArgumentList $VMName -ScriptBlock { 
          Get-VMHardDiskDrive -VMName $VMName
        ($VMDisks.Path | Where { $_ -match ":" }) | % {
          Get-ParentPath -VHDPath $_ -ComputerName $HVName
      and Merge-VMDisks function
  • Saved a lot of time
    2 Posts | Last post January 28, 2019
    • I did use the script and it works perfectly. Our team tuned the script and we found some small errors. Sam if you could please check and update your article accordingly.
      The below process was removed:::
                      #$HVName = Invoke-Command -ComputerName $VM -ErrorAction Stop -ScriptBlock 
                          #$Key = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"
                          #(Get-ItemProperty -Path $Key).PhysicalHostName
      Instead we used 
                      $HVName = 'Put the Hostname'
      Thank you for your kind assistance.
    • Sam we used this powershell script for Windows Server 2012R2.
  • Not ablle to run script
    3 Posts | Last post April 07, 2017
    • Hello
      I am not able to load script to memory
      I run script directly from exlprore or 
      Powershell.exe -executionpolicy Bypass -File D:\Merge-VMDisks.ps1
      but after dat no function like Get-ParentPath, Merge-VMDisks are available.
      Can you help me please, how to load program to memory. (sorry)
    • Import-Module D:\Merge-VMDisks.ps1
      But there is something wrong with it, because script cannot get VM 
      PS D:\>
      PS D:\> Merge-VMDisks -VMName "ntcrack"
      Starting to merge disks on VM(s):
      Computer 'ntcrack' is offline or cannot be contacted.
      Done with VM(s):
    • Guys problem is that regisry key "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest"
      does not contain information about VHHOST (hyperV). I tried to replace it with GET-VMHOST but it not works ,
      Then if you need to merge many avhdX to vhdX just replace
       $HVName = Invoke-Command -ComputerName $VM -ErrorAction Stop -ScriptBlock { 
                          $Key = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"
                          (Get-ItemProperty -Path $Key).PhysicalHostName
      $HVName = 'HOSTNAME'
  • windows 2012 r2 problem
    1 Posts | Last post October 31, 2015
    • Hello, i am running the powershell but i cannot see the functions loading in memory.Ihave tried ise and powershell as administrator.
      Any help?
      Thank you
  • Computer 'VM-Name' is offline or cannot be contacted.
    5 Posts | Last post April 28, 2015
    • Thanks for your new post.
      I still have some Problems, i run ISE as an administrator and can load your function.
      If i run the command i still get an error message
      PS C:\Scripts> Merge-VMDisks -VMName 'VM-Name'
      Starting to merge disks on VM(s):   VM-Name
      Computer 'VM-Name' is offline or cannot be contacted.
      Done with VM(s): 'VM-Name'
      I am Running Hyper-V on Windows 2012 R2 Data Center
    • You should replace 'VM-Name' with the name of the VM :) 
      For example, if the VM name is 'MyCoolPC1', you should run:
      Merge-VMDisks -VMName 'MyCoolPC1'
      If you get the message above using your VM name in the VMName argument, then that means what it says. Specifically a WMI call to the VM has failed. This will occur if the VM is offline, or not responding to WMI calls for one reason or another.
    • I used the machine names instead of VM-Name ...
      The machine is online, responding to Client request and 
      responding to the Hyper-V Manager.
      I exported, the machine deleted the machine and created a new one.
      Now the machine is accessible.
      Seems to be a Problem with old vm comming from Hyper-V (2008 -> 2012 -> 2012 R2)
    • Hi Sam,
      the script is still failing , here is the part that´s not working.
      $Key = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"
      (Get-ItemProperty -Path $Key).PhysicalHostName
      The registry Key on all of my Hyper-V Servers (2012 R2) is empty.
      If i hardcode the query the script will work fine.
      $HVName=Host Name ...
      Can you check this?
    • This key is used by the script to identify the name of the Hyper-V Host that's currently hosting the VM, whose disks we're trying to merge. It's important to obtain that information dynamically, since VMs do live migrate across hosts and static host information of a VM often changes. 
      The script block:
      $HVName = Invoke-Command -ComputerName $VM -ErrorAction Stop -ScriptBlock { 
                          $Key = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"
                          (Get-ItemProperty -Path $Key).PhysicalHostName
      goes out to the VM, and reads that key from there.
      Just to clarify terminology used:
      Guest = VM = Virtual machine = child partition = machine running on synthetic hardware
      Host = Physical machine = Hyper-V Host = Parent partition = machine running on physical hardware
      Server = a term that should not be used in a conversation about virtualization since it describes an operating system role and can apply to both host and guest machines.
  • Windows 2012 R2 Support
    3 Posts | Last post March 28, 2015
    • I tried the script with some orphaned checkpoint on my Windows 2012 R2 Servers.
      The script does nothing.
      Do you have a new Version available?
    • Are you running Powershell ISE 'as administrator'?
    • Jurgen, 
      Running the PS1 file will load its functions into memory. You need to invoke the function Merge-VMDisks as you would any PS cmdlet after that. See this post for more details: https://superwidgets.wordpress.com/2015/03/28/running-powershell-script-functions/