In this post we are going to look at using a PowerShell script to automate the process of a planned fail over on multiple replicated Hyper-V virtual machines, on both domain and workgroup servers.
What the script does:
- Requests for user input specifying the Hyper-V source host
- Requests whether All VM’s need to be migrated or just one
- Retrieves a list of all or one of the hosted virtual machines on that host
- One by one, it checks if the VM is running, and whether replication is enabled
- If VM has a status of ‘running’, the script will shut it down and perform a planned failover. The VM is started after failover and replication is reversed
- If VM has a status of ‘off’, the script will directly perform a planned failover. The VM is not started after failover, replication is reversed
- Has user proof looping to avoid users having to restart the script if the wrong inputs are submitted.
If the Hyper-V hosts are apart of a domain and aren’t in workgroups – please make the following changes to the script, currently it is setup for workgroup hosts.
- Remove $Cert variable – This contains the thumbprint id for the workgroup setup certificates
- Remove -CertificateThumbprint $Cert from the command that reverses the replication (multiple instances in the script).
Set-VMReplication –Reverse –VMName $VM.Name -ComputerName $DestinationHost -CertificateThumbprint $Cert -Confirm:$false -ErrorAction Stop
Changes Required Regardless –
- Change the host names at the start of the script to match your Hyper-V servers. (HYPERVHOST1 / HYPERVHOST2)
Showcase! – excuse the black boxes, they are hiding hostnames
Inputs and information before the script starts the replication process –
End of the script after it’s failed over the Virtual machines –
Full Script –
$Success = 0 #If success < 0 pass loop Do { Write-Host " " $SourceHost = Read-Host "Enter the name of the source host, containing the VM you want to failover: " #Ask for source Hyper-V server with current hosts $ListVMs = Get-VM | Format-Table Name, State, Uptime, Status -auto # Gets a list of VM's if ($SourceHost -eq 'HYPERVHOST1') { $DestinationHost = 'HYPERVHOST2' $Cert = "F1CE5D17A579237CB6EF0F1CC7743035324A46CB" #(DELETE IF HOSTS ARE IN DOMAIN)ForWorkGroupHosts-thumbprint of the certificate your Hyper-V hosts use $Success = 1 } elseif ($SourceHost -eq 'HYPERVHOST2') { $DestinationHost = 'HYPERVHOST1' $Cert = "A6E0CED0C600D6E7919A433266CFA0A8443B18D6" #(DELETE IF HOSTS ARE IN DOMAIN)ForWorkGroupHosts-thumbprint of the certificate your Hyper-V hosts use $Success = 1 } else { Write-Host " " Write-Host 'Invalid source Hyper-V host. Please specify a valid Hyper-V host server' -ForegroundColor Red Write-Host " " } } While ($Success -eq 0) $Success = 0 Do { Write-Host " " $Servers = Read-Host "Do you want to failover all VMs or only one {All or One}" #User makes the choice between moving all VM's or just One if ($Servers -eq 'All'){ #If All is selected, $VMs will contain all Virtual Machines on the hosts $VMs = Get-VM -ComputerName $SourceHost $Success = 1 } elseif ($Servers -eq 'One'){ #If One is selected, $VMs will contain the one specified Virtual Machine Write-host " " Write-host "List of VMs: " -ForegroundColor Yellow $ListVMs Do{ try{ $SpefServers = Read-host "Please input the name of the VM you want to failover " $VMs = Get-VM -name $SpefServers -ComputerName $SourceHost -ErrorAction Stop $Success = 1 } catch { Write-host " " Write-host "Incorrect VM name specified - Please re-run the script and enter the correct HostName for the VM" -ForegroundColor Red Write-host " " $Success = 0 } } While ($VMs.Name -ne $SpefServers) } Else { Write-host " " Write-host "Neither 'One' or 'All' was input - please try again" -ForegroundColor Red Write-host " " $Success = 0 } } While ($Success -eq 0) #Presents the current user input and asks for confirmation before executed Write-host ' ' Write-host "You selected to failover:" $Servers "VM(s)" -ForegroundColor Yellow Write-host 'Hyper-V source host: ' $SourceHost Write-host 'Hyper-V destination host: '$DestinationHost Write-host 'Planned failover from '$SourceHost 'to' $DestinationHost $Success = 0 Do { Write-host " " $Responce = Read-Host "Please confirm you are happy to start the planned failover process - Input 'Yes' to confirm" If ($Responce -eq "Yes"){ Write-host "Continuing script ...." $Success = 1 } Else { Write-host " " Write-host "Wrong Input - Please try again" -ForegroundColor Red Write-host " " Write-host "If you aren't happy with your previous decisions please re-run the script" -ForegroundColor Red } } While ($Success -eq 0) foreach ($VM in $VMs) #Goes through list of VM's whether its one or all and preforms the following on each { $VMName = $VM.Name $SkipVM = 0 if ($VM.State -eq 'Running') #shutdown VM if running { try { $GetVMReplicaDetails = Get-VMReplication -VMName $VM.Name -ErrorAction Stop #Makes sure replication is enabled } catch { Write-Host "Replication is not enabled for the virtual machine $VMName. Skipping it" -ForegroundColor Yellow Continue } try { Write-Host " " Write-Host "$SourceHost- Stopping virtual machine: $VMName" Stop-VM -ComputerName $SourceHost -Name $VM.Name -Force -ErrorAction Stop $State = (Get-VM $VM.Name -ComputerName $SourceHost).State #State variable for use with loop below. Precautionary only do #Looping to wait for VM to be in a shut down state. Precautionary only, command above only finishes executing when the VM is off { $State = (Get-VM $VM.Name -ComputerName $SourceHost).State Start-Sleep -Seconds 5 } while ($State -eq 'Running') } catch { Write-Host " " Write-Error -Message "$SourceHost - Failed to shut down $VMName, skipping!" Continue } if ($SkipVM -eq 0) #Future use { try { Write-Host "$SourceHost- Failing over virtual machine: $VMName" Start-VMFailover –Prepare –VMName $VM.Name -ComputerName $SourceHost -Confirm:$false -ErrorAction Stop Start-VMFailover –VMName $VM.Name -ComputerName $DestinationHost -Confirm:$false -ErrorAction Stop Set-VMReplication –Reverse –VMName $VM.Name -ComputerName $DestinationHost -CertificateThumbprint $Cert -Confirm:$false -ErrorAction Stop Write-Host "$DestinationHost- Powering on virtual machine: $VMName" Start-VM –VMName $VM.Name -ComputerName $DestinationHost -ErrorAction Stop Write-Host " " Write-Host "$VMName has been failed over from $SourceHost to $DestinationHost and has been started" -ForegroundColor Green } catch { Write-Error "$VMName failed to failover to $DestinationHost" Continue } } } elseif ($VM.State -eq 'Off') #If VM is already in a turned off state { try { $GetVMReplicaDetails = Get-VMReplication -VMName $VM.Name -ErrorAction Stop #Makes sure replication is enabled } catch { Write-Host " " Write-Host "Replication is not enabled for the virtual machine $VMName. Skipping it" Continue } #This section is needed if initial input for Hyper-V Host server was not FQDN $CheckPrimaryHost = $GetVMReplicaDetails.PrimaryServer + '.' #Should always return FQDN, but just in case, '.' is added $CheckPrimaryHost = $CheckPrimaryHost.SubString(0, $CheckPrimaryHost.IndexOf('.')) if ($CheckPrimaryHost -eq $SourceHost) #If the VM is primary on the chosen source HV server, failover will proceed. { try { Write-Host " " Write-Host "$SourceHost- Failing over the already turned off virtual machine $VMName" Start-VMFailover –Prepare –VMName $VM.Name -ComputerName $SourceHost -Confirm:$false -ErrorAction Stop Start-VMFailover –VMName $VM.Name -ComputerName $DestinationHost -Confirm:$false -ErrorAction Stop Set-VMReplication –Reverse –VMName $VM.Name -ComputerName $DestinationHost -CertificateThumbprint $Cert -Confirm:$false -ErrorAction Stop Write-Host " " Write-Host "$VMName has been failed over from $SourceHost to $DestinationHost" -ForegroundColor Green } catch { Write-Host " " Write-Error "$VMName failed to failover to $DestinationHost" Continue } } else { Write-Host " " Write-Host "The virtual machine $VMName cannot be failed over -" -ForegroundColor Yellow Write-Host "The specified Hyper-V source host is hosting the replicated VM and not the primary" -ForegroundColor Yellow Write-Host " " Write-host "Please re-run the script and make sure to specify the correct Hyper-V source host" -ForegroundColor Red $host.enternestedprompt() } } else { Write-host " " Write-Host "VM is either in a bad state/running please address then re-run script" -foreground Red Write-Host " " $host.enternestedprompt() } } #Overiew showing all VM's current primary and replica host servers and further clarification for the user $ReplVMs = Get-VMReplication | Format-Table Name, Health, PrimaryServer, ReplicaServer -auto Write-host " " Write-host " " Write-host "____________________________________________" Write-host "Overview:" Write-host " " Write-host "Primary Server should now be:"$DestinationHost "for all the failed over VM(s)" -ForegroundColor Yellow $ReplVMs; $ListVMs = $VMs | Format-Table Name, State, Uptime, Status -auto; $ListVMs Write-host "**You can now close the script**" Write-host " " $host.enternestedprompt()
Hope this is helpful – any idea or comments on the code please feel free to reply to this post below.
Thanks for reading – feel free to follow and stay updated 🙂 View sysadminguides’s profile on Facebook View GuidesSysadmin’s profile on Twitter View 115372466162675927272’s profile on Google+
Hello, very good post, but if a query arises, it is an automatic failure, that is to say that my server 1 is damaged my server 2 in operation automatically? the servers have the VMS in replication.
LikeLike
Hi, Cameron!
Thank you for all your work. It helped me a great deal when I was making my own script for different replication variations. If you’re interested, take a look:https://www.hyper-v.io/powershell-wizard-script-configure-hyper-v-replica-different-scenarios-domain-workgroups-mixed-option/
LikeLike
I need to when I make shutdown to the vm at the hyper v cluster the VM at the DR site RUN automatic without any action from me .
LikeLike