Note: Just like the original script, I had a first idea about a way to do these checks and you will still find traces of it in Veeam forums, however the ongoing discussion has lead to this updatedversion, and it’s really different from the original code, and much better. Kudos for Powershell code goes to my colleague Tom Sightler, if you find this script useful say thanks to him.
In 2012 I published a post with a Powershell script to be able to check all the available VM’s in a given vSphere environment, and verify that Veeam Backup & Replication was taking backups of all my VMs. Time to update the script to make it work with the latest versions of the two software.
Why you want this check
There are situations where it’s easy to verify that every virtual machine that needs to be backed up, it’s effectively protected. But if you are managing hundreds or thousands of VM’s, or you have a highly dynamic environment where VM creation and deletion is frequent, or there are many sysadmins working together, in all these situations there may be changes in the VM list, and if not all of these are configured in the backup jobs one by one, you can dangerously forget some of them… and find it out only when you would need a restore that you cannot complete.
To ease this problem, there is a preventive method as using containers instead of VM lists. If for example you use a resource pool as your backup object, or a datastore or the entire vCenter structure, VM list is created dynamically at every backup execution because the list is read from vCenter everytime. But what if a completely new resource pool or a datastore is created, but not added to the backup jobs? Or maybe someone of the admins have previously excluded a single VM from a backup job, maybe because it was only a test machine he didn’t not want to save, but then this machine became a production machine, and still was not protected.
The checking script
To solve these problems, you can run a Powershell script to check the status of your backups. The previous script was using some unsupported calls that have been since removed from Veeam Backup & Replication. But here it is the new and again functioning 2016 edition!
This script can be executed on the Veeam Server or from any remote workstation using the Standalone Console and the Connect-VBRServer cmdlet. The script looks for every vcenter and single ESXi registered in Veeam Backup & Replication, and retrieves the complete list of all existing virtual machines. No credential is needed as the script uses the same registered in Veeam Backup server itelf.
The script then checks for each of the VM’s if there is a backup (with Success or Warning result) in the last 24 hours. You can change this value by modifying the variable $HourstoCheck = 24
After you you run the script, the result will be like this:
Protected VMs are coloured in green, unprotected in red. This is a super-easy way to check which VMs are protected, and correct your omissions. By changing 24 hours value, you can go back in time to check non daily backups. or as in my case, there is a VM that is replicated daily. The original VM is already protected, but I’m not interested to have a backup also of the replica. So I can use the exclusion list also available in the options of the script, and re-run the script.
As explained in the script itself, to exclude VM’s from the report you can add VM names to be excluded as follows:
# $excludevms=@("vm1","vm2", "*_replica") $excludeVMs = @()
In my example, if I’ve used the default suffix “_replica” to name replicated VM’s, I can immediately excluse any replica from the script:
You can also exclude entire VM folders or entire Datacenters, if needed.
This is the complete script code, enjoy!
# # Verify protected VM's # #################################################################### # # MIT License # #Copyright (c) 2016 Tom Sightler # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # #################################################################### # # Run the script against vCenter and Veeam server and checks which VM's # have been protected in the last 23 hours, and which are not protected asnp "VeeamPSSnapIn" -ErrorAction SilentlyContinue #################################################################### # Configuration # # To exclude VMs from report add VM names to be excluded as follows # simple wildcards are supported: # $excludevms=@("vm1","vm2", "*_replica") $excludeVMs = @("") # Exclude VMs in the following vCenter folder(s) (does not exclude sub-folders) # $excludeFolder = = @("folder1","folder2","*_testonly") $excludeFolder = @("") # Exclude VMs in the following vCenter datacenter(s) # $excludeDC = = @("dc1","dc2","dc*") $excludeDC = @("")# # This variable sets the number of hours of session history to # search for a successul backup of a VM before considering a VM # "Unprotected". For example, the default of "24" tells the script # to search for all successful/warning session in the last 24 hours # and if a VM is not found then assume that VM is "unprotected". $HourstoCheck = 24 #################################################################### # Convert exclusion list to simple regular expression $excludevms_regex = ('(?i)^(' + (($excludeVMs | ForEach {[regex]::escape($_)}) -join "|") + ')$') -replace "\\\*", ".*" $excludefolder_regex = ('(?i)^(' + (($excludeFolder | ForEach {[regex]::escape($_)}) -join "|") + ')$') -replace "\\\*", ".*" $excludedc_regex = ('(?i)^(' + (($excludeDC | ForEach {[regex]::escape($_)}) -join "|") + ')$') -replace "\\\*", ".*" $vms=@{} # Build a hash table of all VMs. Key is either Job Object Id (for any VM ever in a Veeam job) or vCenter ID+MoRef # Assume unprotected (!), and populate Cluster, DataCenter, and Name fields for hash key value Find-VBRViEntity | Where-Object {$_.Type -eq "Vm" -and $_.VmFolderName -notmatch $excludefolder_regex} | Where-Object {$_.Name -notmatch $excludevms_regex} | Where-Object {$_.Path.Split("\")[1] -notmatch $excludedc_regex} | ForEach {$vms.Add(($_.FindObject().Id, $_.Id -ne $null)[0], @("!", $_.Path.Split("\")[1], $_.Path.Split("\")[2], $_.Name))} Find-VBRViEntity -VMsandTemplates | Where-Object {$_.Type -eq "Vm" -and $_.IsTemplate -eq "True" -and $_.VmFolderName -notmatch $excludefolder_regex} | Where-Object {$_.Name -notmatch $excludevms_regex} | Where-Object {$_.Path.Split("\")[1] -notmatch $excludedc_regex} | ForEach {$vms.Add(($_.FindObject().Id, $_.Id -ne $null)[0], @("!", $_.Path.Split("\")[1], $_.VmHostName, $_.Name))} # Find all backup task sessions that have ended in the last x hours and not ending in Failure $vbrtasksessions = (Get-VBRBackupSession | Where-Object {$_.JobType -eq "Backup" -and $_.EndTime -ge (Get-Date).addhours(-$HourstoCheck)}) | Get-VBRTaskSession | Where-Object {$_.Status -ne "Failed"} # Compare VM list to session list and update found VMs status to "Protected" If ($vbrtasksessions) { Foreach ($vmtask in $vbrtasksessions) { If($vms.ContainsKey($vmtask.Info.ObjectId)) { $vms[$vmtask.Info.ObjectId][0]=$vmtask.JobName } } } $vms = $vms.GetEnumerator() | Sort-Object Value # Output VMs in color coded format based on status # VM's with a job name of "!" were not found in any job foreach ($vm in $vms) { if ($vm.Value[0] -ne "!") { write-host -foregroundcolor green (($vm.Value[1]) + "\" + ($vm.Value[2]) + "\" + ($vm.Value[3])) "is backed up in job:" $vm.Value[0] } else { write-host -foregroundcolor red (($vm.Value[1]) + "\" + ($vm.Value[2]) + "\" + ($vm.Value[3])) "is not found in any backup session in the last" $HourstoCheck "hours" } }