How to SureBackup a lot of VMs (v2)

How to SureBackup a lot of VMs (v2)

If you read these lines, your probably know the Veeam Backup & Replication (VBR) feature SureBackup. It is a perfect tool to verify backups of well known applications within your organization. SureBackup can perform a lot of different tests while VMs are running in an isolated environment. You can also use custom scripts for further testing. But how to test all other VMs? These Simple VMs that usually make up the majority of an environment. These can be hundreds or even thousands. SureBackup can’t be configured in console for these VMs realistically. This post shows how to simply SureBackup a lot of VMs.

This topic isn’t new, of course. The following PowerShell script is based on the great script of Luca Dell’Oca: How can you test 1000 VMs with Veeam SureBackup. My script includes a lot of new features as you will see – therefore: v2.

New Features

  • Old SureBackup cmdlets have been replaced by new ones, introduced with VBR v10.
  • With this version, all Startup Options can be configured.
  • When the Backup job of a selected VM is currently running, VM will be skipped and re-evaluated at next run.
  • Mail can be sent using SureBackup job notification.
  • Because of a missing implementation, VBR v11 is not able to script SureBackup for backup jobs selecting VMs by vSphere tag. My script including a workaround to enable this functionality.


# Variables for script ------------------------
$AppGroupName = "Dynamic App Group"
$SbJobName = "Dynamic Surebackup Job"
$SbJobDesc = "Dynamic App Testing"
$Date = (Get-Date).AddDays(-30)
$VirtualLab = "VirtualLab Name"
$eMail = ""
$VBRserver = "VBR Server"

# Variables for function selectUntestedVMs
[string]$VeeamBackupCounterFile = "C:\Scripts\SureBackup\VMtable.xml"
# How many VMs should be tested at once?
[int]$NumberofVMs = 1

# Functions -----------------------------------
Function selectUntestedVMs
    $fVMTable = @()
    $fTestVMs = [System.Collections.ArrayList]@()
    $fDeletedVMs = [System.Collections.ArrayList]@()
    # Import VMtable if exists from a previous iteration
    if(Test-Path $fVeeamBackupCounterFile)
        $fVMTable = import-clixml $fVeeamBackupCounterFile
    # Check if all VM's were tested
    # if so the VMTable is cleared
    if(!($fVMTable.Checked -contains 0)) {$fVMTable = @()}
    # Add newly created VM's from backup
    Foreach($fVbrObj in $fVbrObjs)
        if(!(($fVMTable.VMname) -Contains ($
            $fVMTable += [PSCustomObject] @{
                        VMname = $fVbrObj.Name;
                        JobName = $fVbrObj.JobName;
                        Checked = 0;
                        Deleted = 0}
    # Remove old VM's from VMTable
    $fVMTable | foreach { if($ -notcontains $_.VMname) {$_.Deleted = 1}}
    # Sort VMTable by Checked and VMname
    $fVMTable = $fVMTable | Where-Object {$_.Deleted -eq 0} | Sort-Object Checked, VMname
    # Select least tested VMs and set as Checked
    $fTestVMs = @()    
    for ($i = 0; $fTestVMs.Length -lt $fNumberofVMs; $i++)
    # Check if backup job currently running. If so, skip VM for a later run
        if   ((Get-VBRBackupSession -Name ($fVMTable[$i].JobName + "*") | Where-Object {$_.state -ne "Stopped" -and $_.EndTime.Year -eq 1900}) -eq $null) { 
            $fTestVMs += [PSCustomObject] @{
                          VMName = $fVMTable[$i].VMname;
                          JobName = $fVMTable[$i].JobName}
            $fVMTable[$i].Checked = 1
    #Save VMTable to file for the next iteration
    $fVMTable | Export-Clixml $fVeeamBackupCounterFile
    Return $fTestVMs
# Since VBR v11 Veeam delivers a PowerShell module instead of a SnapIn.
# In case you run the script in a v10 environment, run this line
# asnp "VeeamPSSnapIn" -ErrorAction SilentlyContinue
Connect-VBRServer -Server $VBRserver

# Here all available Verification Options can be set
$VbsStartOptions = New-VBRSureBackupStartupOptions -AllocatedMemory 100 -EnableVMHeartbeatCheck:$true -EnableVMPingCheck:$false -MaximumBootTime 1800 -ApplicationInitializationTimeout 0 

#Check if Application Group exists
if(!(Get-VSBApplicationGroup -Name $AppGroupName)) {
    # Find all VM objest successfully backed sind $Date
    $VbrObjs = (Get-VBRBackupSession | Where-Object  {$_.JobType -eq "Backup" -and $_.EndTime -ge $Date}).GetTaskSessions() | Where-Object {$_.Status -eq "Success" -or $_.Status -eq "Warning" }
    # Call function selectUntestedVMs
    $TestVMs = selectUntestedVMs -fVeeamBackupCounterFile $VeeamBackupCounterFile -fNumberofVMs $NumberofVMs -fVbrObjs $VbrObjs

    # Build VM list to test using new cmdlet New-VBRSureBackupVM
    $SbVMs = @()
    foreach ($TestVM in $TestVMs) {
        $TestVMObject = Find-VBRViEntity -Name $TestVM.VMname
        $TestVMVbrJob = Get-VBRJob -Name $TestVM.Jobname

        $VbrJobObject = Get-VBRJobObject -Job $TestVMVbrJob -name $TestVMObject.Name | Where-Object {$_.type -eq "Include"}
        [switch]$VmAdded = $false
        if ($VbrJobObject -eq $null) {
            Add-VBRViJobObject -Job $TestVMVbrJob -Entities $TestVMObject 
            $VbrJobObject = Get-VBRJobObject -Job $TestVMVbrJob -name $TestVMObject.Name | Where-Object {$_.type -eq "Include"}
            $VmAdded = $true
        $SbVMs += New-VBRSureBackupVM -VM $VbrJobObject -StartupOptions $VbsStartOptions
        if ($VmAdded) {Remove-VBRJobObject -Objects $VbrJobObject -Completely}
    $AppGroup = Add-VBRViApplicationGroup -Name $AppGroupName -VM $SbVMs}

else {
        Write-Host "App Group" $AppGroupName "already exists, please clean up your mess"

# Check if SureBackup job exists
if(!(get-vsbjob -Name $SbJobName)) {

    $VirtualLab = Get-VBRVirtualLab -Name $VirtualLab    
    $VsbJob = Add-VBRViSureBackupJob -Name $SbJobName -VirtualLab $VirtualLab -ApplicationGroup $AppGroup -Description $SbJobDesc -KeepApplicationGroupRunning:$false

    if ($email -ne $null) {
        $SbJobVerficationOptions = New-VBRSureBackupJobVerificationOptions -Address $email
        Set-VBRViSureBackupJob -Job $VsbJob -VerificationOptions $SbJobVerficationOptions
    Start-VBRSureBackupJob -Job $VsbJob

    # Remove the old App Group, SureBackup Job, Disconnect from Server after running
    Remove-VBRSureBackupJob -Job $VsbJob -Confirm:$false
    Remove-VBRApplicationGroup -ApplicationGroup $AppGroup

else {
        Write-Host "SureBackup Job" $SbJobName "already exists, please clean up your mess"

What the script does

High-level steps of the script:

  1. [Line 82] Defining Startup Options for VM verification.
  2. [Line 87] Reading backup sessions (VMs) of last 30 days ($Date).
  3. [Line 89] Select VMs for testing (function selectUntestedVMs) .
    1. [Line 26-34] Read VMtable; if all VMs are already tested, new VMtable will be created.
    2. [Line 37-50] Add new VMs and remove VMs that does not exist any more.
    3. [Line 59-66] Sort VMtable and check if associated backup job is currently running. Take first $NumberofVMs VMs with no running job.
    4. [Line 69] Save VMtable to $VeeamBackupCounterFile.
  4. [Line 92-108] Create application group for selected VMs. This section includes the mentioned workaround.
  5. [Line 115-124] Create and start SureBackup job.
  6. [Line 127-130] Clean up.


Implementation is quite simple. Required is a correct Virtual Lab configuration. Its name is set in variable $VirtualLab. Provide suitable data for all variables at the beginning of the script. To be mentioned here:

  • $Date
    Time interval which is used to query restore points. If there are no restore points for a VM within this interval, it will not be tested.
  • $VeeamBackupCounterFile
    Absolute path to the file containing the list of VMs that have been tested so far or are still pending.
  • $NumberofVMs
    Number of VMs that are selected for a single SureBackup run.

Set your preferred parameter for Startup Options in line 82. With that, script is ready to run and can be tested manually. When everything works fine, you can schedule the script with Windows scheduler.


  • When adding more than one VM to a SureBackup job, the job will fail – and therefore stop – when first VM fails. Therefore do not add too many VMs to a job, otherwise some VMs will not be tested.
  • Without changes, it is not possible to run this script several times simultaneously. This is because a SureBackup job locks the Virtual Lab.
  • At the time of writing, there is a bug in VBR v11 PowerShell module. Cmdlet Remove-VBRSureBackupJob removes ALL SureBackup jobs.
  • Should be clear, nevertheless: Script is “as is”! I do not guarantee its functionality nor I am responsible for anything it does in your environment.


7 responses to “How to SureBackup a lot of VMs (v2)”

  1. Randy Lee says:

    Great content!

  2. Hi,
    Just testing this script.

    This command for me is deleting all SureBackup jobs. Looks like some bug.
    Remove-VBRSureBackupJob -Job $VsbJob -Confirm:$false

    The old command works correctly.
    Remove-VSBJob -Job (Get-VSBJob -Name $VsbJob.Name) -Confirm:$false

    To test just create any SB job in the GUI,
    Then run the script.
    Go back to the GUI.
    Did it delete your SB job.

    Ver Veeam 11..0.1.1261

    • vNote42 says:

      You are right, this is a – already known – bug. I mentioned this in Consideration (3rd point):
      “At the time of writing, there is a bug in VBR v11 PowerShell module. Cmdlet Remove-VBRSureBackupJob removes ALL SureBackup jobs.”

  3. Steve says:

    Hi Wolfgang,

    a customer asked me to update your script to run under VBR V12. Here’s the result:


  4. Steve says:

    Update: Move the script from the Playground to the VBR section. Changed some variables to be handled as parameters and wrote a short Readme:


  5. Richard says:

    I updated the script so you can filter the backup job by name.

Leave a Reply

Your email address will not be published. Required fields are marked *