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
}