Merge VHD help

Feb 9, 2010 at 9:39 AM

Hi,

 

What is the paramters to run the merge script ?

i have tried everything for merging VHD and parent path and it does not work.


 

# Merge VHDs

param(
    [string]$mergePath = $(throw "Must specify full path for merging VHD"),
    [string]$parentPath = $(throw "Must specify full path of parent VHD")
)

#obtain the Msvm_ImageManagementService class
$ImageMgtService = get-wmiobject -class "Msvm_ImageManagementService" -namespace "root\virtualization"

# Create the fixed VHD
$result = $ImageMgtService.MergeVirtualHardDisk($mergePath,$parentPath)

if($result.ReturnValue -eq 4096){
    # A Job was started, and can be tracked using its Msvm_Job instance
    $job = [wmi]$result.Job
    # Wait for job to finish
    while($job.jobstate -lt 7){$job.get()}
    # Return the Job's error code
    return $job.ErrorCode
}
# Otherwise, the method completed
return $result.ReturnValue

Coordinator
Feb 10, 2010 at 9:28 AM

Sorry, I'm having to make some guesses here as I don't know what error you're getting, or if you have tried to adapt the code that is posted here, or what operation you are trying to perform

However.... when I see

# Create the fixed VHD

It makes me think you are trying to take a differencing VHD and convert it into fixed VHD. This is a convert operation, and you tell convert the source (it determines the parent of the differencing VHD) the destination (a new file) and if you want the result to be a dynamic or fixed VHD file.  

Merge is the operation of taking a snapshots AVHD file and merging into its parent VHD or AVHD.

 

Feb 10, 2010 at 9:41 AM

Hi,

 

Thanks for the reply.

The above script was download from http://pshyperv.codeplex.com/ called Merge-VHD

I get the error code 32774 or 32773 which means invalid peramaters.

 

Coordinator
Feb 11, 2010 at 3:59 PM

Hmmm. I can't find a version which looks like that, so if it did come from here it's pretty old.

Anyhow,  are you trying to merge differing disks to a new disk (in which case use convert) or combine the changes since a snapshot into the disk as it was before the snapshot was taken (which IS merge). ?

Could you please try the current download and see of that works as you need ?

 

 

Feb 11, 2010 at 7:22 PM

Hi,

Ok let me explain.

I am taking snapshot each night using a script i found:

##
##    Take a snapshot of all the vm's
##

$VM_Service = get-wmiobject -namespace root\virtualization Msvm_VirtualSystemManagementService
$ListofVMs = get-wmiobject -namespace root\virtualization Msvm_ComputerSystem -filter  "ElementName <> Name "   


foreach ($VM in [array] $ListOfVMs)
{
    $VM_service.CreateVirtualSystemSnapShot($VM.__PATH)
}



##
##    Giving Hyper-V 30 sec to take the snapshots
##

Start-Sleep(30)



##
##    Remove snapshots older than 6 days (except Sundays)
##

$VSVR = get-wmiobject -namespace root\virtualization -class Msvm_ComputerSystem
$VSSNAP = get-wmiobject -namespace root\virtualization -class Msvm_VirtualSystemSettingData -filter "SettingType = 5"

if (!($VSSNAP -eq $null))
{
    foreach ($SS in [array] $VSSNAP)
    {
        if ($SS.ConvertToDateTime($SS.CreationTime) -le [DateTime]::Now.AddDays(-6).Date)
        {
            if (!($SS.ConvertToDateTime($SS.CreationTime).DayOfWeek -eq 0))
            {
                $VM_Service.RemoveVirtualSystemSnapshot($SS)
                Start-Sleep(3)
            }
        }
    }
}


This works great however i am going to end up with a lot of avhd files. If i shutdown the vm, it will merge all the old deleted snapshots.
I want a script to do this during the night automatically in the background without shutting down the vm :)

Can this be done ?

Coordinator
Feb 11, 2010 at 7:37 PM

I'm going to need to double check my facts, but I'm pretty sure you can't merge while the VM is running.  Because a merge happens when the VM is shutdown there are very few occasions you'd need to run one manually (like working with a copy of the vhd and avhd files that have been exported).

 

Feb 28, 2011 at 3:13 PM

 

This is a piece of code that I wrote that I believe does what your looking for, it does the following:

1. Shuts down each VM
2. Takes a snapshot of the VM and waits 30 seconds
3. Starts the VM
4. Copies the Snapshot off to our DR Hyper-V server
5. Shuts down the VM and tells it to remove the snapshots (merge them)
6. Allows the snapshot to merge wiats 90 seconds
7. Starts the VM
8. Writes each step to Copy.txt 
9. moves on to the next VM

10. After all VM have been copied, mails the copy.txt to our support group. 

VM's are located in D:\VM-Config
VM Drives are located in D:\VM-Drive 
Scripts are located in D:\VM-Backup-Script 

I run this as a scheduled task using a cmd file. 
The file must be run as a user that has Admin rights on both Hyper-V servers.

CMD Code:

PowerShell "D:\VM-Backup-Script\new-backup-multi.PS1" /wait

Power Shell Code: (new-backup-multi.PS1)

Set-ExecutionPolicy unrestricted -force
import-module "C:\Program Files\HyperV_Powershell\hyperv.psd1"
Remove-Item D:\VM-Backup-Script\copy.txt
$arrComps = "Server1", "Server2", "Server3"
Start-Transcript D:\VM-Backup-Script\copy.txt
foreach ($arrComps in $arrComps)
{
invoke-vmshutdown $arrComps -force
new-vmsnapshot $arrComps -force -waitstart-sleep -s 30
Start-VM $arrComps -HeartBeatTimeOut 300

$date = Get-Date -format yyyy-MM-dd
New-Item \\phys-hvb\d$\VM-Drives\$date -type directory -force
Copy-Item D:\VM-Drives\$arrComps\*.vhd \\Remote-Server\d$\VM-Drives\$date\
select-vmsnapshot $arrComps | remove-vmsnapshot -wait -tree -force
invoke-vmshutdown $arrComps -force
start-sleep -s 90
Start-VM $arrComps -HeartBeatTimeOut 300
}
Stop-Transcript

$fileData = (Get-Content "D:\VM-Backup-Script\copy.txt" | out-string)
$file = "D:\VM-Backup-Script\copy.txt"
$smtpServer = "your SMTP relay Server"
$msg = new-object Net.Mail.MailMessage
$att = new-object Net.Mail.Attachment($file)
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = "Your-Server@mail.com"
$msg.To.Add("Recipient@mail.com")
$msg.Subject = "Hyper-V Backup Results"
$msg.Body = $fileData
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()