As part of some recent testing, I had the need for a quick and easy backup tool for creating imaged-based backups of my various virtual machines and appliances.
To get moving quickly I decided to use a little tool called ghettoVCB created by William Lam (https://www.virtuallyghetto.com/2015/05/ghettovcb-vib-offline-bundle-for-esxi.html). It’s easy to install, has a near zero learning curve, and before I knew it I was happily taking backups of everything I could see.
Evolution of ghettoVCB-wrapper.ps1
ghettoVCB is a host based tool i.e. it is executed on the ESXi host that the VM is running on, so I started out creating a PowerShell wrapper that uses vCenter to determine the host the VM is on, before SSH’ing into the host, and kicking off the backup.
As my testing progressed, and I deleted VMs and restored them from backups taken with ghettoVCB I realised that in so doing I was losing some detail (on the appliances in particular), namely:
- OVF Properties.
- Folder and Resource Pool settings.
- DRS Affinity Rules and DRS VM Groups used for VM to VM Dependencies.
And some appliances rely on the OVF properties at every boot, not just the first one.
Because ghettoVCB runs at the host level, it doesn’t have access to the above details. So I started expanding my scripts to capture this information during the backup and storing it in a JSON file for restoration later on. And of course actually restoring those values too.
And so the ghettoVCB-wrapper.ps1 was born
I had all sorts of fun figuring out the permutations for restore. Some examples:
- When you take a backup of an Anti-Affiny rule you really need to capture information on all the VMs in the rule. Then, assuming you have blown away all the VMs, you cannot add just one VM to the rule when restoring the first VM – as affinity rules must have at least two VMs. So you need to wait until all the VMs are back before repairing the rule. So I wrote some code that doesn’t rebuild the DRS group until the last VM of the set is back.
- Note, this actually deletes the rule and re-creates it. Full disclosure!
- When you delete VMs, DRS VM Groups are technically left in an invalid state in that they are empty. Normally you cant remove the last VM from a group without deleting the group itself. Set-DrsClusterGroup wont allow you to add one VM to that group, it expects there to be a member already. So I had to write some different code to get around the first VM. The subsequent ones all use Set-DrsClusterGroup to get back into the group.
It’s not the finished article, and I’ll lay out some obvious areas for improvement in a moment, but the heavy lifting is done, and it certainly makes my testing more efficient. Here’s a brief list of the functions and how to operate the tool.
Here’s a list of functions used in the file. They are not exported or anything, but feel free to take what I’ve done and make it better. I did contemplate a PowerGhettoVCB, but I thought I’d post this first and maybe come back to that later.
- Generic function I use in most of my scripts for making the catch blocks shorter and more informative when its called
- Originally also written by William Lam, this is my modified version that allow for colours, skipping of new line, and logging to file in addition to time stamps
- Wrapper function for all the VM backup settings, which compiles and saves the output in a JSON in the same location as the script itself
- Grabs the OVF settings on the VM, and passes it back for storage
- Grabs the Folder and Resource Pool locations for the VM and passes them back for storage
- Grabs the DRS Affinity Rules and DRS VM Groups locations for the VM and passes them back for storage
- When passed an OVF property read in from a backup file will construct and reapply the property on the restored VM
- When passed the OVF IP Assignment settings read in from a backup file will reapply the settings on the restored VM
- When passed the OVF Env Transport settings read in from a backup file will reapply the settings on the restored VM
- When passed an OVF product read in from a backup file will construct and reapply the product on the restored VM
- When passed the OVF EULA settings read in from a backup file will reapply the settings on the restored VM
- Used to add that first restored VM to an empty DRS VM Group. Others will use Set-DrsClusterGroup
- Uses vCenter to find the host the VM runs on, connects to the host via SSH, backs up the VM, parses the output for backup status
- Connects to user supplied host via SSH, searches for backup of the VM, restores it, parses the output for successful backup status
Make sure you have a connection to vCenter
PS C:\> Connect-VIServer vc01.mydomain.local -user Administrator@vsphere.local -pass MyLovelyPa$$w0rd
Setup the two global variables at the start of the script that configure where the backups should be saved to (and searched in for), as well as the datastore where VMs should be restored to.
$Global:backupLocation = 'myNFSDatastore/backups' $Global:targetDatastore = 'myTargetVSANDatastore'
Create a ‘configurations’ folder on in the backupLocation above, and store the following two configuration files that are also in the git repo
PS C:\> ghettoVCB-wrapper.ps1 -backup -vm vmname -quiesce disabled -esxiRootPassword $esxiRootPassword
- Passing the -quiesce disabled with use the .conf file with the disabled option set
- Passing with -quiesce enabled with use the .conf file with the enabled option set
You should see output something like the below
C:\> ghettoVCB-wrapper.ps1 -restore -vm vmname -esxihost myhost01.mydomain.local -esxiRootPassword $esxiRootPassword
This will connect to myhost01 and restore the backup. You should see something a little like this
There is also a -ovfonly flag which skips the VM restore if you have done it already and just restores the OVF Properties. The VM groups and Affinity rules being a simple point and click effort. If you wanted to do those manually.
Areas for Improvement
Things I thought of and might get to in the future.
- My backup .conf files limit the backup count to 1 as I was space constrained. It would be nice to expand that back to to 3 and allow the user to select which one to restore
- It would be simple enough to have a backup file created and stored with the backup on the datastore rather than locally with the script
- Have the functions create a ‘per vm’ .conf file, possibly as a standalone operation before backup and restore e.g. a New-BackupConfiguration function which takes all the required settings for a VM and creates a bespoke settings file in the configurations folder based on the VM name (and adjust the backup code to look at said file).
- Exporting the functions, turning it into a proper module
- Making for parallel backups of multiple VMs in a list, using Start-Job etc.
- Maybe splitting the actual execution into two separate cmdlets for backup and restore
Code is available here
Enjoy, and as always…..feedback welcome!