Hyper-V Replication via PowerShell

I wanted to replicate a few VMs from one computer to another. These are just Windows 10 pro VMs running Hyper-V. I know most people would just use the Windows Server Hyper-V built-in replication functionality but I’m not running that OS. So here is the poor-man’s way of replicating the VMs and setting up automatic startup with PowerShell. Keep in mind that these Hyper-V hosts are both in the domain for this to work properly (this is mostly just for the SMB/CIFS file transfer).

The code below just needs paths and hostnames filled in. You’ll need to create a shared folder on the destination host as well. Then you can run this script as a scheduled task on both hosts. It needs more work but should cover basic functionality.

#holds primary copies, controls what script does on each computer
$hv_primary = "primary_hostname"

#filter out VMs by notes field
$critical_tag = "CRITICAL_VM"

switch ($env:computername) {
	"primary_hostname" { $hv_partner = "secondary_hostname" }
	"secondary_hostname" { $hv_partner = "primary_hostname" }
	default { exit }
}

if ($env:computername -eq $hv_primary) { 
	#run primary server functions
	
	if ((Test-NetConnection -ComputerName $hv_partner).PingSucceeded -eq $true) {
		write-host "partner $hv_partner is online. copy vm files to him."
		
		Get-VM | where {$_.Notes -match $critical_tag } | foreach {
		
			if (test-path ("\\$hv_partner\Hyper-V\" + $_.Name)) {
				write-host ("need to remove old copy first. path: " + ("\\$hv_partner\Hyper-V\" + $_.Name))
				remove-item -force -recurse ("\\$hv_partner\Hyper-V\" + $_.Name)
			} else {
				write-host ("exporting it now. path: " + "\\$hv_partner\Hyper-V\" + $_.Name)
				Export-VM -VM (get-vm $_.Name) -Path "\\$hv_partner\Hyper-V\"
			}
		}
	}

} else {
	#run backup server functions (ensure we have VMs that are recent, test if primary online and boot if primary off.

	
	#ensure partner is online
	if ((Test-NetConnection -ComputerName $hv_partner).PingSucceeded -eq $true) {
		write-host "partner $hv_partner is online. no need to fire up VM's on this end."
		
		write-host "ensure our VM's are off. stop them now if running."
		Get-VM | where {$_.Notes -match $critical_tag } | where {$_.State -eq "Running"} | stop-vm
		
	} else {
		write-host "partner $hv_partner is NOT online."
		
		write-host "checking if VMs imported yet or not."
		$vm_list = (GCI "\\$env:computername\Hyper-V\" | ?{ $_.PSIsContainer })
		
		$vm_list | foreach {
			$this_vm_dir = $_

			write-host "check if this VM $($this_vm_dir.Name) is already imported"
			$this_vm = Get-VM ($this_vm_dir.Name)
			
			if ($this_vm) {
				write-host "this VM $($this_vm_dir.Name) is already imported"
			} else {
				write-host "importing VM $($this_vm_dir.Name) now."
				
				$this_vm_guid_path = (gci ($this_vm_dir.FullName + "\" + "Virtual Machines") | where { $_.Name -match ".xml"}).FullName
				
				if ($this_vm_guid_path) {
					write-host "GUID Path: $($this_vm_guid_path)"
					Import-VM -Path $this_vm_guid_path
				} else {
					write-host "this vm is in an older format. finding GUID a different way."
					
					$this_vm_guid_path = (gci ($this_vm_dir.FullName + "\" + "Virtual Machines"))[0].FullName
					write-host "GUID Path: $($this_vm_guid_path)"
					Import-VM -Path $this_vm_guid_path
				}
			}
			
			remove-variable this_vm_dir, this_vm, this_vm_guid_path
		}
		
		write-host "starting my copy's VMs up now."
		Get-VM | where {$_.Notes -match $critical_tag } | where {$_.State -eq "Off"} | start-vm
	}

}



This entry was posted in IT and tagged . Bookmark the permalink.

Leave a Reply