If you look after ESXi hosts that are installed to SD cards then you will know the constant pain of replacing failed cards. You may know the pain of losing both cards in this process and having to reinstall from scratch. ESXi hosts are not the hardest thing to rebuild but for me. its a job I don’t have time for.
So this is a script that basically connects to a list of vCenters, loops through each host and runs the following
Get-VMHostFirmware -VMHost $vHost -BackupConfiguration -DestinationPath $BackupFolder
It will then append the date to the backup file name and delete any old/unneeded backup files.
It will also produce a text file of the host basic config details. name, mgt IP, mgt vlan, version etc.
So in the event you lost the host you will to reinstall ESXi to the same version. connect to it and import the backup. Job done.
To set the script up all you need is a CSV file with a list of vCenters and if needed path to exported credentials and a location for the backups.
The vCenter CSV should be in the following format
Location,vCenterIP,vCenterName,Enable,CredFile
eg
Production-London, 10.10.10.10, prod-vc01.domain.name , y, c:\script\SavedCreds\BackupAccountCred.xml
Here is the script. It has saved me a lot of rebuild / reconfig time. It even works for hosts is a cluster using NSX.
Import-module VMware.VimAutomation.Core
$vCenterCSVFile = "c:\Scripts\Backup\Locations\vcenters.csv"
$ResultFile = "c:\Scripts\Backup\Logs\BackupResult.csv"
$LogFile = "c:\Scripts\Backup\Logs\HostBackup.log"
$BackupBaseDirectory = "\\BackupServer\Share\BackupPath\ESXiBackups"
$KeepOldBackups = 4
$BackupResult = @()
$vCenters = import-csv $vCenterCSVFile
# loop through each vCenter listed in the csv file
foreach ($vCenter in $vCenters)
{
# disconnect if connected to VC
if ($global:DefaultVIServers){disconnect-viserver * -Confirm:$false}
# connect to VC
$UseCreds = $false
try
{
if(test-path $vCenter.CredFile){$UseCreds = $true}
}
catch
{
$UseCreds = $false
}
# if we have a valid cred file path, import creds and use them to connect to vCenter
if ($useCreds)
{
$Credentials = Import-CliXml -Path $vCenter.CredFile
$ConnectionDetails = connect-viserver $vCenter.vCenterIP -Credential $Credentials
}else{
$ConnectionDetails = connect-viserver $vCenter.vCenterIP
}
# test connection to VC
if (($global:DefaultVIServers).name -eq $vCenter.vCenterIP)
{
# check/create backup paths
if(!(test-path $BackupBaseDirectory)){New-Item -ItemType directory -Path $BackupBaseDirectory}
$BackupPODFolder = $BackupBaseDirectory + "\" + $vCenter.Location
if(!(test-path $BackupPODFolder)){New-Item -ItemType directory -Path $BackupPODFolder}
# loop through each host in the vCenter
foreach($vHost in Get-VMHost)
{
# check backup path exists, create if not.
$BackupFolder = $BackupBaseDirectory + "\" + $vCenter.Location + "\" + $vHost.name
if(!(test-path $BackupFolder)){New-Item -ItemType directory -Path $BackupFolder}
# get the date as a string so we can append it to the backup file name later.
$BackUpDate = get-date -f "yyyy-MM-dd"
# get host info (This will be used to build the $NetFile)
# The NetFile is a summery of the host config (IP details. version etc)
$HostNetworking = $vHost | Get-VMHostNetwork
$MGTnet = @($HostNetworking.VirtualNic | where {$_.ManagementTrafficEnabled -eq $true})[0]
$HostIP = $MGTnet.IP
# get result object ready
$tmpResult = '' | select Location,Host,Backup
$tmpResult.Location = $vCenter.Location
$tmpResult.Host = $vHost.name
$BackupStatus = Get-VMHostFirmware -VMHost $vHost -BackupConfiguration -DestinationPath $BackupFolder
if ($?)
{
$tmpResult.Backup = "Success"
$BackupFilePath = $BackupStatus.Data
#write host info to file
$NetFile = $BackupFolder + "\NetworkInfo.txt"
"HostName: " + $vHost.name | out-file $NetFile
"HostIP: " + $MGTnet.IP | out-file $NetFile -Append
"Subnet mask: " + $MGTnet.SubnetMask | out-file $NetFile -Append
"MAC address: " + $MGTnet.MAC | out-file $NetFile -Append
"Gateway: " + $HostNetworking.VMKernelGateway | out-file $NetFile -Append
"Port Group: " + $MGTnet.PortGroupName | out-file $NetFile -Append
"DNS Servers: " + @($HostNetworking.DnsAddress) -join " " | out-file $NetFile -Append
"Domain Name: " + $HostNetworking.DomainName | out-file $NetFile -Append
"Version: " + $vHost.Version + " " + $vHost.Build | out-file $NetFile -Append
"Model " + $vHost.Manufacturer + " " + $vHost.Model | out-file $NetFile -Append
'' | out-file $NetFile -Append
"To restore. Open PowerCLI and run" | out-file $NetFile -Append
"connect-viserver $HostIP" | out-file $NetFile -Append
"Set-VMHost -VMHost $HostIP -State 'Maintenance'" | out-file $NetFile -Append
"Set-VMHostFirmware -VMHost $HostIP -Restore -SourcePath $BackupFilePath" | out-file $NetFile -Append
# get the file object of the most recent backup file (this one) and append the data on the end
$CurrentBackUpFile = get-item ($BackupFolder + "\config*") | sort lastwritetime | select -last 1
rename-item ($CurrentBackUpFile.FullName) -NewName ($CurrentBackUpFile.name).Replace(".tgz",("-" + $BackUpDate + ".tgz")) -Confirm:$false
# remove any old backups over the file keep limit
$FileToDelete = get-item ($BackupFolder + "\config*") | sort lastwritetime -Descending | select -Skip $KeepOldBackups
if ($FileToDelete){remove-item $FileToDelete -Confirm:$false}
}else{
$tmpResult.Backup = "Failed"
}
$BackupResult += $tmpResult
"Backup of host " + $tmpResult.Host + " in POD " + $tmpResult.Location + " " + $tmpResult.Backup
} # end loop through each host
Disconnect-VIServer * -confirm:$false
}else{
# not connected to the correct VC. do nothing.
}
}
$BackupResult | export-csv $ResultFile -NoTypeInformation
# number of successful and failed backups. currently not doing anything with them
$SuccBackups = @($BackupResult | where{$_.backup -eq "Success"}).count
$failedBackups = @($BackupResult | where{$_.backup -eq "Failed"}).count