Thursday, September 15, 2016

Instant VM restore

This script is used to instantly restore a virtual machine from a netapp flexcloned volume

###################################################
#$filercreds is defined in profile.ps1 if you dont have it in your profile.ps1 - uncomment the following
##Run this part once
#read-host -AsSecureString | ConvertFrom-SecureString | out-file c:\filerpassword.txt

##Add this part to your profile.ps1
#$filerpassword = cat C:\filerpassword.txt | ConvertTo-SecureString
#$Filercreds = New-Object -TypeName System.Management.Automation.PScredential -argumentlist "admin" , $filerpassword
#################################################


Connect-VIServer vserver1,vserver2
$RecoveryVM = read-host "Enter the name of the VM that you want to do an instant restore"

$sanityCheck = read-host "By proceeding you will be removing" $RecoveryVM "from the invenotry and then mounting and running the VM from a flexclone - the script will then migrate the VM from the flexclone and overwrite the old production volume and dismount the flexclone - Proceed (Y/N)"
If ($sanityCheck -like "*N*")
    {write-host "exiting"
     pause
     exit }

$recoveryVM = get-vm | Where-Object {$_.name -like $RecoveryVM}
$recoveryhost = get-vm $recoveryvm | get-vmhost
$RecoveryVMParentStorage = get-vm $RecoveryVM | get-datastore | Where-object {($_.name -notlike "*swap*") -and ($_.name -notlike "*srm*") -and ($_.name -notlike "*page*")}

If ($RecoveryVMParentStorage.count -gt 1)
    { Write-host "Attached disks span more than 1 netapp volume - you'll have to do a manual restore using SMVI"
      Pause
      exit
    }

get-vm $recoveryvm | Shutdown-VMGuest -Confirm:$false

$i = 0
do{
    $i++
    Write-host "waiting for shutdown to complete"
    sleep 1
    $powerstate = get-vm $RecoveryVM
    if ($i -gt 120){
    write-host "VM is not shutting down gracefully - performing power off"
      get-vm $RecoveryVM | stop-vm -Confirm:$false
                    }
    }until($powerstate.powerstate -like "*off*")


remove-vm $recoveryvm -Confirm:$false  

# Connect to the appropriate filer
            if ($RecoveryVMParentStorage -like "*filera*"){
                 Connect-NcController namefilera -Credential $Filercreds -Vserver filera1              
                }
            if ($RecoveryVMParentStorage -like "*filerb*"){
                 Connect-NcController namefilerb -Credential $Filercreds -Vserver filerb1                
                }

$NetappVols = get-ncvol $RecoveryVMParentStorage.name

foreach ($netappvol in $NetappVols){
$AllNetavols = get-ncvol $netappvol | Get-NcSnapshot
}


# Create a list box containing all snapshots from the volume - Partially plagerised from https://technet.microsoft.com/en-us/library/ff730949.aspx

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Select a snapshot to clone"
$objForm.Size = New-Object System.Drawing.Size(300,200)
$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
    {$x=$objListBox.SelectedItem;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
    {$objForm.Close()}})

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({$x=$objListBox.SelectedItem;$objForm.Close()})
$objForm.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)

$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(280,20)
$objLabel.Text = "Available Snapshots for $NetappVols.name :"
$objForm.Controls.Add($objLabel)

$objListBox = New-Object System.Windows.Forms.ListBox
$objListBox.Location = New-Object System.Drawing.Size(10,40)
$objListBox.Size = New-Object System.Drawing.Size(260,20)
$objListBox.Height = 80


foreach ($AllNetavol in $AllNetavols){
[void] $objListBox.Items.Add($AllNetavol.name )
}

$objForm.Controls.Add($objListBox)

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()



# get the flexclone as selected by the user
$Flexclone = get-ncvol $netappvol | get-ncsnapshot | Where-object {$_.name -like $objListBox.SelectedItem}

$FlexcloneVolname = $netappvol.name+"FC_InstantRestore"

#Check if the volume is already present - if it is warn the user and exit
if (Get-Datastore | Where-Object {$_.name -like $FlexcloneVolname}) {
        Clear
        write-host "*** Error*** The volume" $FlexcloneVolname "already exists - check there are no VMs running on it , unmount it and rerun the script"
        Pause
        exit
}
   

# spawn the flexcloned volume from the snapshot
get-ncvol $netappvol | New-NcVolClone -CloneVolume $FlexcloneVolname -ParentSnapshot $Flexclone

# figure out which host to attach the export to , Create the export , attach the export
$recoveryhostIP = $recoveryhost | Get-VMHostNetworkAdapter
$exportIPS = $recoveryhostIP.ip | Where-Object {$_ -cmatch $RecoveryVMParentStorage.remotehost.Split(".")[2]}
Get-Ncvol $FlexcloneVolname | Mount-NcVol -JunctionPath "/$FlexcloneVolname"
Add-NcNfsExport -Path /$FlexcloneVolname -ReadWrite @($exportIPS) -Root @($exportIPS)
Sleep 30
New-Datastore -VMHost $recoveryhost -Name $FlexcloneVolname  -Path /$FlexcloneVolname -NfsHost $RecoveryVMParentStorage.remotehost -Nfs

# Set up Search for .VMX Files in Datastore (partially plagerised from http://www.wooditwork.com/2011/08/11/adding-vmx-files-to-vcenter-inventory-with-powercli-gets-even-easier/)
   $ds = Get-Datastore -Name $FlexcloneVolname | %{Get-View $_.Id}
   $SearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
   $SearchSpec.matchpattern = "*.vmx"
   $dsBrowser = Get-View $ds.browser
   $DatastorePath = "[" + $ds.Summary.Name + "]"

   # Find all .VMX file paths in Datastore, filtering out ones with .snapshot (Useful for NetApp NFS)
   $VMXfile = $dsBrowser.SearchDatastoreSubFolders($DatastorePath, $SearchSpec) | where {($_.FolderPath -notmatch ".snapshot") -and ($_.folderpath -cmatch $RecoveryVM.name)} | %{$_.FolderPath + ($_.File | select Path).Path}

   #Register the .vmx Files
   New-VM -VMFilePath $VMXFile -VMHost $recoveryhost -Location $recoveryVM.Folder -ResourcePool $RecoveryVM.ResourcePool -RunAsync
 

#Wait until the VM has been registered on the vcentre server
            do {
                Write-host "confirming that " $recoveryvm "is registered on vcentre server before continuing -"
                $VMwaiter = get-vm $recoveryvm -erroraction silentlycontinue
                Sleep 5
                }
                until ($VMwaiter)

# start the VM up and answer the VM startup question
        get-vm $RecoveryVM | start-vm  -Confirm:$false -ErrorAction SilentlyContinue
            Sleep 20
        get-vm $RecoveryVM | Get-VMQuestion | Set-VMQuestion -Option button.uuid.copiedTheVM -Confirm:$false -ErrorAction SilentlyContinue



Write-host "VM has been started on flexclone Volume - beginning Storage vmotion to" $recoveryVMparentstorage " you can begin using the VM now"

#svmotion the VM back to the original location
  get-vm $RecoveryVM | move-vm -Datastore $RecoveryVMParentStorage -DiskStorageFormat Thin -VMotionPriority High
 


#Wait for the VM to complete svmotion
    do {
        $VMwaiter = get-vm $recoveryvm | get-datastore | Where-object {($_.name -notlike "*swap*") -and ($_.name -notlike "*srm*")}
        Write-host  "waiting for VM to complete svmotioning"
        sleep 10
        }
        until ($vmwaiter -like $RecoveryVMParentStorage)


#Trigger a SIS on the original volume
start-ncsis -path $netappvol -scan

#cleanup + remove recovery volume from ESXi Host and export & Volume from filer
Remove-Datastore -VMHost $recoveryhost -Datastore $FlexcloneVolname -Confirm:$false
#Determine the export policy Name - if its default then abort
$exportpolicyName = Get-NcVol $FlexcloneVolname |  select @{n="PolicyName"; E={ $_.VolumeExportAttributes.policy}}
 If ($exportpolicyName.policyname -notlike "*Default*"){
  remove-ncnfsexport -paths /$FlexcloneVolname -Confirm:$false
  Dismount-NcVol -Name $FlexcloneVolname -Confirm:$false
  set-ncvol $FlexcloneVolname -Offline -Confirm:$false
  Remove-NcVol $FlexcloneVolname -confirm:$false
  get-ncexportpolicy | Where-object {$_.PolicyName -like $exportpolicyname.policyname} | Remove-NcExportPolicy -Confirm:$false
    }

 Else{
 write-host "Trying to modify Default policy - Aborting"
 Pause
 }











No comments:

Post a Comment