I think it’s a safe bet to say that most of vCenter servers out there are virtualized nowadays. In the end if you trust Vmware to virtualize your mission critical business applications why not run vCenter in a virtual machine, especially that vCenter itself is not a critical component of vSphere infrastructure (unless you’re hosting/cloud provider using functionality like Chargeback etc).
So you’ve got your vCenter virtual, secured by Vmware HA and just to be on the safe side you create backup clone(s) of this server on regular basis.
Cloning vCenter for backup purposes is fully supported, about one year ago Artur posted a PowerCLI script to automate this task.
But then the Friday 13th comes, something bad happens, you can not get your vCenter running and you don’t want to leave your infrastructure “unmanaged” over the weekend, so you decide to use that backup clone and restore your vCenter.
You “power on” the cloned vm just to recognize that (if your vCenter is Windows – and I think large part of vCenter servers still is) your IP configuration inside Windows is gone :S.
This is because cloned vm receives new MAC address(es) for each virtual nic and subsequently Windows detects these vnics as new, unconfigured hardware (which makes some sense tbh).
Then you need to manually configure the IP settings of your vCenter, which is really annoying if you planned to go home early this Friday.
What about we extend the functionality of the script that creates the clone to also save IP configuration somewhere in a form that can be used to restore this settings by another script?
The only place to safely store this IP configuration file is of course vCenter itself, we assume no networking connectivity during restore, so it can not be network share of any kind and if we save this configuration file before making the clone it will be copied with the whole server, right?
Artur’s script after modification should look like this:
Add-PSSnapin VMware.VimAutomation.Core #variables $VC='vcenter-server-FQDN-or-IP' #import credentials $pwd = Get-Content D:\tools\scripts\ap-vcs-credentials | ConvertTo-SecureString $credentials = New-Object System.Management.Automation.PsCredential “username“, $pwd $ScriptRoot = Split-Path $MyInvocation.MyCommand.Path $xml_output = "$ScriptRoot\vcenter_nics_ipconfig.xml" #create array of objects representing ip settings of all vmware network adapters $nics = @(get-wmiobject win32_networkadapterconfiguration | where-object {$_.macaddress -like "00:50:56:*"} | select-object description, ipaddress, ipsubnet, defaultipgateway, dnsserversearchorder | sort-object -descending -property index) #export configuration to xml file $nics | export-clixml -path $xml_output #Connect to vCenter Connect-VIServer -Server $VC $sourceVM = 'test01' #in $respool you can specify ESX host, cluster or resource pool $respool=Get-VMhost -Name "ESXi host name" $datastore=Get-datastore -Name 'datastore name' $cloneName = $sourceVM+'-01' #Remove second copy of VM Remove-VM $sourceVM'-02' -Confirm:$false -DeletePermanently:$true #Rename latest VM copy Get-VM -Name $sourceVM'-01' | Set-VM -Name $sourceVM'-02' -confirm:$false #Clone VM if(New-VM -Name $cloneName -VM $sourceVM -ResourcePool $respool -Datastore $datastore -DiskStorageFormat Thin ){"DONE"}else{"Something wrong with cloning"} Disconnect-VIServer -Confirm:$false
The IP configuration is exported to vcenter_nics_ipconfig.xml file (I assume you run this script from vCenter itself, as a Windows Scheduled Task probably) just before connecting vCenter to create the clone.
The restoring of this IP configuration can be somewhat tricky, mainly because Windows not only detects vnics as a new hardware but also (if you have more than one vnic in your vCenter) there is no easy way to detect the order in which they are connected (at least I couldn’t figure out anything workable, probably it can be done if you save also PCI IDs of your vnics along with IP configuration).
In general – there is no problem with vCenter that has one vnic only (obviously), when there are two vnics (like I usually have) the solution (or workaround to the problem) is fairly easy, you just try one order of configuration, test the connectivity (ping the default gateway probably – and there should be only one default gateway, right?) if it doesn’t work – just try the reverse order (and the script below does all of that for you)
<# .SYNOPSIS Script configures vmware network adapters to ip settings loaded from vcenter_nics.xml file .DESCRIPTION This script can be useful in scenario of cloning and restoring (virtual machine) vcenter server After clone is restored vnics receive new MAC addresses and subsequently are detected as new hardware in Windows, with no ip configuration The script creates array of current ($new_nics) WMI win32_networkadapterconfiguration objects that have vmware specific MAC addres prefix (00:50:56: ) then sorts it in descending order of "index" property It is assumed that the higher number of vnic in vmware the higher number of network adapter index in windows (i. e. Network adapter 1 in vmware <-> Network adapter index #7 in windows AND Network adapter 2 in vmware <-> Network adapter index #8 in windows) UNFORTUNATELY THIS IS NOT ALWAYS TRUE The script tries to detect and handle possible error by testing connectivity (ping) to default gateway (should always be only one in any system!) If ping is successful it is assumed ip configuration is OK If unsuccessful script tries to apply the settings in reverse order and test ping again That should do the trick for conifgurations with no more than 2 nics you know ;) If you have more than 2 nics and still no connectivity after 2nd ping attempt - you're on your own ;) After array of current nics is created the ip configuration is loaded from vcenter_nics_ipconfig.xml file, this file should be created before cloning vcenter using store_vcenter_ipconfig.ps1 script With a little interaction from administrator using the script (it is assumed restore from clone is not completely automated operation) a for loop assigns ip configuration so that it matches configuration stored in .xml file .PARAMETER <paramName> none .EXAMPLE trivia #> #general scope variables $ScriptRoot = Split-Path $MyInvocation.MyCommand.Path $xml_input = "$ScriptRoot\vcenter_nics_ipconfig.xml" #create array of objects representing ip settings of all current vmware network adapters $new_nics = @(get-wmiobject win32_networkadapterconfiguration | where-object {$_.macaddress -like "00:50:56:*"} | sort-object -descending -property index) $old_nics = import-clixml -path $xml_input $new_nics_count = $new_nics.count $old_nics_count = $old_nics.count #write what will be done to the screen write-host "CURRENT nic count is $new_nics_count" -foreground green write-host "STORED nic count is $old_nics_count" -foreground red write-host "This script will set following configuration" -foreground green for ($i=0; $i -lt $old_nics_count; $i++) { #using index 0 for ipaddress properties is to make sure IPv4 address is selected $ip = $old_nics[$i].ipaddress[0] $subnet = $old_nics[$i].ipsubnet[0] $gateway = $old_nics[$i].defaultipgateway $dns = $old_nics[$i].dnsserversearchorder write-host $new_nics[$i].macaddress will get address $ip and subnet $subnet write-host $new_nics[$i].macaddress will get gateway $gateway write-host $new_nics[$i].macaddress will get dns $dns } #give the engineer performing restore chance to abort write-host "This is your LAST CHANCE TO ABORT" -foreground yellow write-host "STOP NOW If STORED nic count doesn't match CURRENT nic count or if you see any ip misconfiguration" -foreground red write-host "Press Y + ENTER to continue" -foreground green write-host "Press any other key + ENTER to ABORT..." -nonewline -foreground red $response = read-host if ( $response -ne "Y" ) { write-host "Operation ABORTED, no changes have been made to network settings" -foreground red #exit } else { #assume there is no connectivity $ping_test = $false for ($i=0; $i -lt $old_nics_count; $i++) { #using index 0 for ipaddress properties is to make sure IPv4 address is selected $ip = $old_nics[$i].ipaddress[0] $subnet = $old_nics[$i].ipsubnet[0] $gateway = $old_nics[$i].defaultipgateway $dns = $old_nics[$i].dnsserversearchorder #this is where we finally change these IPs write-host Setting $new_nics[$i].macaddress with address $ip and subnet $subnet $new_nics[$i].enablestatic($ip, $subnet) | out-null write-host Setting $new_nics[$i].macaddress with gateway $gateway $new_nics[$i].setgateways($gateway) | out-null write-host Setting $new_nics[$i].macaddress with dns $dns $new_nics[$i].setdnsserversearchorder($dns) | out-null #try to ping default gateway if ((!$ping_test) -and $gateway) { write-host "TESTING network settings..." -foreground yellow $ping_test = test-connection $gateway -quiet } } #if received pong from default gateway we assume configuration is OK if ($ping_test) { write-host "PING to default gateway successful" -foreground green write-host "Assuming IP configuration is correct... My work here is D0N3" -foreground green write-host "It's a good idea to REBOOT NOW" -foreground green #exit } else { #damn, no pongs try to reconfigure nics in reverse order write-host "OOPS, no ping response from default gateway, trying reverse nic order" -foreground yellow $new_nics_asc = @(get-wmiobject win32_networkadapterconfiguration | where-object {$_.macaddress -like "00:50:56:*"} | sort-object -property index) #well this is false anyway, but I copy-pasted it just to be sure $ping_test = $false for ($i=0; $i -lt $old_nics_count; $i++) { #using index 0 for ipaddress properties is to make sure IPv4 address is selected $ip = $old_nics[$i].ipaddress[0] $subnet = $old_nics[$i].ipsubnet[0] $gateway = $old_nics[$i].defaultipgateway $dns = $old_nics[$i].dnsserversearchorder #last attempt to set-up IPs write-host Setting $new_nics_asc[$i].macaddress with address $ip and subnet $subnet $new_nics_asc[$i].enablestatic($ip, $subnet) | out-null write-host Setting $new_nics_asc[$i].macaddress with gateway $gateway $new_nics_asc[$i].setgateways($gateway) | out-null write-host Setting $new_nics_asc[$i].macaddress with dns $dns $new_nics_asc[$i].setdnsserversearchorder($dns) | out-null #and ping the gateway again if ((!$ping_test) -and $gateway) { write-host "TESTING network settings AGAIN..." -foreground yellow $ping_test = test-connection $gateway -quiet } } #if true we quit happy, otherwise we give up if ($ping_test) { write-host "PING to default gateway successful" -foreground green write-host "Assuming IP configuration is correct... My work here is D0N3" -foreground green write-host "It's a good idea to REBOOT NOW" -foreground green #exit } else { write-host "OOPS, STILL no ping from default gateway, I have no idea what to do next... Exiting :( " -foreground red #exit } } }
The script is a bit interactive – it requires you to confirm you want to apply IP configuration stored in .xml file, I just don’t trust myself enough to let it run in fully automated mode (especially on Friday the 13th 😉 ).
It will probably not work (unless you’re lucky) with 3 and more vnics in vCenter – there is simply more than 2 possible permutations of vnics order, but why would you need more than 2 vnics in vCenter anyways? 😉
Also note that it doesn’t configure things like DNS search suffixes or persistent routes (if you have any), but it can be easily extended to do so.
I actually had “real life” opportunity to see this script working and it did it’s job – restored vCenter connectivity to the point where I could go home for the weekend and finish minor things (like these DNS suffixes) on Monday.
I hope you find this script useful, any comments are welcome!