Poor Man’s Virtual Machine Backup with PowerCLI

Are you still performing old-school in-guest VM backups with a backup agent? Not ready to buy a backup product that does complete VM backups through the vStorage APIs? Then you will need to rebuild all your VM’s with the original configuration before you can start restoring your data.

As always: PowerCLI to the rescue! This script will connect to vCenter Servers on your primary site and secondary (recovery) site. It scans the datastores on the primary site for vmx files and copies them to a designated datastore on the secondary site. (It uses a local temp location, because direct copy from one vCenter to another is not possible.)

When you add these vmx files to the inventory on the secondary site, you’ll notice the disks are either not available or have a zero size. That’s because the size is listed in the vmdk files, not the vmx. Copying the vmdk descriptors as well might sound like a nice solution to this challenge, but this will not help due to absolute paths being used to locate the vmdk files.

Another challenge lies in the fact that the VM name, the OS host name and the vmx file name might not be identical.

To solve both problems, the script gathers all this information for you – vm names, OS host names, vmx names and disk sizes – stores it in a csv file and uploads it to the same datastore in the secondary datacenter. This way you are all set to recover your VM’s on the cheap!

#DISCLAIMER# You still need the old school backup to restore your data! This script just helps rebuild the empty VM’s in your recovery location.

# Created by https://www.peetersonline.nl
$VerbosePreference = "Continue" # Use "Continue" to show verbose information during interactive use. Use "SilentlyContinue" to hide verbose info during non-interactive use.
Write-Verbose "====================="
Write-Verbose "VM Config Copy Script"
Write-Verbose "Copies VMX files and an overview of remaining important VM configuration to a remote datastore (via local TEMP folder) "
Write-Verbose "====================="
#REGION Variables
$vCenterSource = 'PrimaryVC.domain.local' # Source vCenter Server (Primary Site)
$vCenterDestination = 'SecondaryVC.domain.local' # Destination vCenter Server (Secondary Site)
$DestinationDatastore = "MY-DATASTORE-01" # Destination datastore (Secondary Site)
$Temp = (Get-Item Env:\TEMP).Value # Path to local temp folder (on host running this script)
Write-Verbose "vCenter Source : $vCenterSource"
Write-Verbose "vCenter Destination : $vCenterDestination"
Write-Verbose "Destination : $DestinationDatastore"
Write-Verbose "Temp Folder : $Temp"
Write-Verbose "---------------------"
#ENDREGION Variables
#REGION Script
Write-Verbose "Connecting to Source vCenter $vCenterSource..."
$VIServer = Connect-VIServer $vCenterSource
Write-Verbose "Connecting to Destination vCenter $vCenterDestination..."
$VIServer = Connect-VIServer $vCenterDestination
Write-Verbose "Connecting to Destination Datastore $DestinationDatastore..."
$Destination = New-DatastoreDrive -DriveName Destination -Datastore $DestinationDatastore
Write-Verbose "---------------------"
Write-Verbose "Start VMX COPY section"
ForEach ($SourceDatastore in (Get-Datastore -Server $vCenterSource))
Write-Verbose "---------------------"
Write-Verbose "Connecting to source datastore $($SourceDatastore.Name)..."
New-DatastoreDrive -DriveName $SourceDatastore.Name -Datastore $SourceDatastore | Out-Null
ForEach ($VmConfigFile in (Get-ChildItem -Path "$($SourceDatastore.Name):" -Recurse | Where {$_.ItemType -eq "VmConfigFile"}))
Write-Verbose "Copying VmConfigFile $($VmConfigFile.Name) to TEMP..."
Copy-DatastoreItem $VmConfigFile $Temp
Write-Verbose "Copying VmConfigFile $($VmConfigFile.Name) to destination..."
Copy-DatastoreItem "$($Temp)\$($VmConfigFile.Name)" "Destination:\"
Write-Verbose "---------------------"
Write-Verbose "Start VMconfig section"
Write-Verbose "---------------------"
$myCol = @()
ForEach ($VM in (Get-VM -Server $vCenterSource))
$myObj = "" | Select VMName, GuestName, VMX, DiskSizesGB
$myObj.VMName = $VM.Name
$myObj.GuestName = $VM.Guest.HostName
$myObj.VMX = $vm.ExtensionData.Config.Files.VmPathName.Split("/")[-1]
$myObj.DiskSizesGB = ($VM | Get-HardDisk | %{$_.CapacityKB/1024/1024}) -join ";"
$myCol += $myObj
Write-Verbose "Writing VMconfig file to TEMP..."
$myCol | Export-Csv -NoTypeInformation -Path "$($Temp)\VMConfig.csv" | Out-Null
Write-Verbose "Copying VMConfig file to destination..."
Copy-DatastoreItem "$($Temp)\VMConfig.csv" "Destination:\"
Write-Verbose "---------------------"
Write-Verbose "Disconnecting from both vCenter Servers..."
Disconnect-VIServer * -Confirm:$false

Download the script here: Copy-VMXFilesRemote (rename to .ps1)

Close Menu