Automate VM Failover on Hyper-V Replicated hosts – PowerShell Script – Domain & Workgroup

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:

  1. Requests for user input specifying the Hyper-V source host
  2. 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
  3. 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
  4. 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 –

Powershell HyperV

End of the script after it’s failed over the Virtual machines –

Powershell failover HyperV

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+

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s