Here you will find the latest version of the PowerShell/Veeam scripts found on this blog
v9
Veeam v9 – My Veeam Report v9.5.3
v8
Veeam v8 – My Veeam Report turns 2.0!
Veeam v8 – Backing up a single VM with PowerShell
Veeam v8 – Changing Default Options After Upgrade
v7
My Veeam Report v1.2
Veeam – Updating job settings with PowerShell
Documenting Veeam Backup Job Settings
Veeam v7 – Backing up a single VM within a job
Advertisements
Your efforts in version 9.01 have been an incredible help to me in pulling specific information about backup and restore jobs. My first foray into a PowerShell script to derive a .CSV file focused on VMware backups and restores. I now need to expand the script to include Endpoint Backup information. Do you happen to know if there are logs begin written during Endpoint Backup operations that are exposed to the PowerShell environment, similar to the logs that are accessible in restore operations? I’m trying to get the backup size of each Endpoint Backup, and ideally whether the backup was full or incremental. I don’t see that information exposed as elements in Get-VBREPJob or VBREPSession.
For VMware restore operations, I ended up writing a small function to look through the restore job log to pull information. IF similar information is logged for Endpoint jobs, I should be able to parse it.
Admittedly, since Endpoint Backup is still free from Veeam, I understand why they have far fewer PowerPoint hooks in place for EP.
Thank for sharing your great work.
My guess is that these logs exist on the client and not the server. I’ve not seen anything beyond what you have mentioned. It will be interesting to see how they build upon the relationship between VB&R and EP.
Discovered that – for each EPSession, the repository is also creating information on a Restore Point. I was hoping to find an ID that would insure the Restore Point record I’m retrieving matches the Endpoint Protection session, but so far I have not seen how to make that connection. So I look for a restore point that is created during the EP Session.
With apologies for my learning code, no doubt highly inefficient – here’s my current script. Anything good I learned from you. Lots of commented lines as I try different fields and approaches.
param(
[string]$vbrServer=”127.0.0.1″,
[int]$vbrPort=9392,
[string]$vbrUser,
[string]$vbrPassword,
[int]$LookBackHrs=48,
[string]$outFile=””,
[switch]$ConnectTest=$false
)
#$LookBackHrs = 2200 # Controls how many hours back to retrieve backup and restore jobs
#$outFile = “E:\tmp\Veeam_APTARE_GenericBU_$(Get-Date -format MMddyyyy_hhmmss).csv” # Output file name
#$outFile = “E:\tmp\Veeam_APTARE_GenericBU_v5.csv” # Output file name
$Vendor = “‘Veeam'” #VendorName placed in CSV
#$vbrServer = “10.2.3.159” #Veeam Server to be connected
# Set variables to null
$nullstrg=”‘null'”
$outarray=@()
$backuparray=@()
$backupEParray=@()
$restorearray=@()
add-pssnapin “VeeamPSSnapIn” -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
Disconnect-VBRServer
#write-host (‘ConnectTest = ‘ + $ConnectTest)
if ($ConnectTest) {
if (Test-NetConnection -port $vbrPort -Computername $vbrServer -InformationLevel Quiet )
{write-host ‘vbrServer Pings’}
#Exit
else
{write-host (‘ERROR: Unable to connect to ‘+$vbrServer+’. Please verify connectivity to ‘+$vbrServer+’ from collector server using port ‘+ $vbrPort)
Throw (‘Test NetConnection to ‘+$vbrServer+’ on port 9392 fails.’)
Exit
}
}
if ($ConnectTest) {
Try {
Connect-VBRServer -User $vbrUser -Password $vbrPassword -server $vbrServer -Port $vbrPort -ErrorAction Stop -WarningAction Stop -Timeout 1
}
Catch {
Write-Host (‘ERROR: Authentication failed. Verify credentials.’)
Throw ‘Error connecting to Veeam Server. Check credentials’
Exit
}
Write-Host ‘SUCCESS: Successfully connected to Veeam Server’
Exit
}
Try {
Connect-VBRServer -User $vbrUser -Password $vbrPassword -server $vbrServer -Port $vbrPort -ErrorAction Stop -WarningAction Stop -Timeout 5
} Catch {
Throw ‘Error connecting to Veeam Server’
Exit
}
function Convert-HEXtoDECRes
{
param(
[Parameter(ValueFromPipeline=$true, Position=0)]
[string]$HEXr)
$subHEXr=””
$hexrint=””
$subHEXr = $HEXr.Substring(0, $HEXr.IndexOf(“-“) )
ForEach ($value in $subHEXr)
{
$hexrint = [Convert]::ToInt64($value,16) + $hexrint
}
RETURN $hexrint
}
Function Get-RestoreSize {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true, Position=0)]
[string]$Inputstring
)
[hashtable]$RestoreInfo = @{}
If($inputstring) {
If ($inputstring.Contains(“=”)) {
$NbrOfFiles = $inputstring.Substring($inputstring.IndexOf(“=”)+1, $inputstring.IndexOf(“files”)-$inputstring.IndexOf(“=”) -2 )
} else
{ $NbrOfFiles = 0}
If ($inputstring.Contains(“(“)) {
$RestoreString = $Inputstring.Substring($Inputstring.IndexOf(“(“)+1,($Inputstring.IndexOf(“)”)-($Inputstring.IndexOf(“(“)))-1)
[integer]$RestoreSizeVal = $RestoreString.Substring(0,$RestoreString.IndexOf(” “))
$RestoreSizeUnits = $RestoreString.Substring($RestoreString.IndexOf(” “)+1)
$RestoreSizeKB = switch ($RestoreSizeUnits) {
“MB” {[int]$RestoreSizeVal * 1024}
“GB” {[int]$RestoreSizeVal * 1024 * 1024}
“TB” {[int]$RestoreSizeVal * 1024*1024*1024}
“PB” {[int]$RestoreSizeVal * 1024*1024*1024*1024}
default {[int]$RestoreSizeVal}
}
} else
{ $RestoreSizeKB = 0
}
}
$RestoreInfo.NbrofFiles = $NbrOfFiles
$RestoreInfo.RestoreSizeKB = $RestoreSizeKB
Return $RestoreInfo
}
$Backups = Get-VBRBackup -Name “Backup Job ERNIEB-PC”
#$ernie = $Backups.sm # Info
#$ernie
$Jobs = Get-VBRJob -WarningAction SilentlyContinue
foreach ($job in $Jobs) {
$BackupSessionsList = @(Get-VBRBackupSession | ? {($_.CreationTime -ge (Get-Date).AddHours(-$LookBackHrs)) -and $_.JobName -eq $job.Name}) #-and $_.Status -ne “Success”
$RestoreSessionsList = @(Get-VBRRestoreSession | ? {($_.CreationTime -ge (Get-Date).AddHours(-$LookBackHrs)) }) #-and $_.JobName -eq $job.Name}) #-and $_.Status -ne “Success”
$BackupEPSessionsList = @(Get-VBREPSession | ? {($_.CreationTime -ge (Get-Date).AddHours(-$LookBackHrs)) }) # -and $_.JobName -eq $job.Name})
#$BackupEPSessionsList
#
foreach ($tasks in $BackupSessionsList) {
$task = Get-VBRTaskSession $tasks
#[string]$JobIDstring=””
#$JobID=””
#$JobIDstring = $task.Id
#$JobIDstring = $task.Id
#$JobID = Convert-HEXtoDEC $JobIDstring
$backuparray = $task | Select-Object @{Name=”VendorName”;Expression={$Vendor}},
@{Name=”ClientName”; Expression = {“‘”+$_.Name+”‘”}},
@{Name=”ClientIPAddress”; Expression = {$nullstrg}},
#@{Name=”VendorJobType”; Expression = {“‘”+$job.JobType+”‘”}},
@{Name=”VendorJobType”; Expression = {“‘BACKUP'”}},
#@{Name=”JobStatus”; Expression = {$job.JobStatus}},
#@{Name=”Long Job Name”;Expression={$tasks.Name}},
#@{Name=”Job Level”;Expression={$tasks.Name.Substring(($tasks.Name.IndexOf(“(“))+1,($tasks.Name.IndexOf(“)”)-($tasks.Name.IndexOf(“(“)))-1)}},
@{Name=”StartDateString”; Expression = {“‘”+$_.Progress.StartTime.ToString(“yyyy-MM-dd HH:mm:ss”)+”‘”}},
@{Name=”FinishDateString”; Expression = {“‘”+$_.Progress.StopTime.ToString(“yyyy-MM-dd HH:mm:ss”)+”‘”}},
@{Name=”BackupKilobytes”; Expression = {[math]::Round(($_.Progress.ReadSize/1024),1)}},
#@{Name=”TransferedSize in KB”; Expression = {[math]::Round(($_.Progress.TransferedSize/1024),1)}},
@{Name=”NbrOfFiles”; Expression = {$_.Progress.ProcessedObjects}},
@{Name=”MediaType”; Expression = {“‘D'”}},
#Status,
@{Name=”VendorStatus”; Expression = {switch ($_.Status) {
“Success” {0}
“Failed” {2}
default {1}
}
}},
@{Name=”VendorJobID”; Expression = {“‘”+$_.Id+”‘”}},
#@{Name=”VendorJobID”; Expression = {(“‘”+(Convert-HEXtoDECRes $_.Id)+”‘”) }},
#@{Name=”VendorJobID3″; Expression = { “‘”+$JobIDstring+”‘” }},
@{Name=”VendorPolicyName”; Expression={“‘”+$_.JobName+”‘”}},
@{Name=”JobLevel”; Expression={“‘”+$_.Info.WorkDetails.TaskAlgorithm+”‘”}},
#@{Name=”JobLevelSession”;Expression={ $_.JobSess.SessionInfo.SessionAlgorithm}},
@{Name=”TargetName”;Expression={“‘”+$_.JobSess.JobSourceType+”‘”}},
@{Name=”Schedule”; Expression = {“‘”+$_.Schedule+”‘”}}#,
# @{Name=”Details”; Expression = {
# If ($tasks.GetDetails() -eq “”){“‘”+($tasks.GetDetails()).Replace(“`n”,” “).Replace(“”,” – “) + ($tasks | Get-VBRTaskSession | %{If ($tasks.GetDetails()){$tasks.Name + “: ” + $tasks.GetDetails()}})+”‘”}
# Else {(“‘”+$tasks.GetDetails()).Replace(“`n”,” “).Replace(“”,” – “)+”‘”}}} #| Format-Table #| ConvertTo-csv | % {$_ -replace ‘”‘,””} #-auto
$outarray = $outarray + $backuparray
}
foreach ($EPtasks in $BackupEPSessionsList) {
[string]$backupepstring=””
#$EPtasks.sm
#$backupepstring = $Job.Logger.GetLog() #.UpdatedRecords #| Select-Object title
#$backupepstring
#$EPtask = Get-VBREPTaskSession $EPtasks
#write-hosts (‘$EPTask =’ + $EPtask)
#[string]$JobIDstring=””
#$JobID=””
#$JobIDstring = $task.Id
#$JobIDstring = $task.Id
#$JobID = Convert-HEXtoDEC $JobIDstring
$EPJob=””
$EPRestorePoint = Get-VBRRestorePoint | ? {($_.CreationTime -ge ($EPtasks.CreationTime) -and $_.CreationTime -le ($EPtasks.EndTime)) }
$EPJob = Get-VBREPJob -Id $EPRestorePoint.FindSourceJob().Id
#write-host (‘Object Count = ‘ + $EPJob.ObjectsCount)
#$EPRestorePoint
$backupEParray = $EPtasks | Select-Object @{Name=”VendorName”;Expression={$Vendor}},
@{Name=”ClientName”; Expression = {“‘”+$EPRestorePoint.fqdn+”‘”}},
@{Name=”ClientIPAddress”; Expression = {$nullstrg}},
#@{Name=”VendorJobType”; Expression = {“‘”+$job.JobType+”‘”}},
@{Name=”VendorJobType”; Expression = {“‘BACKUP'”}},
#@{Name=”JobStatus”; Expression = {$job.JobStatus}},
#@{Name=”Long Job Name”;Expression={$tasks.Name}},
#@{Name=”Job Level”;Expression={$tasks.Name.Substring(($tasks.Name.IndexOf(“(“))+1,($tasks.Name.IndexOf(“)”)-($tasks.Name.IndexOf(“(“)))-1)}},
@{Name=”StartDateString”; Expression = {“‘”+$_.CreationTime.ToString(“yyyy-MM-dd HH:mm:ss”)+”‘”}},
@{Name=”FinishDateString”; Expression = {“‘”+$_.EndTime.ToString(“yyyy-MM-dd HH:mm:ss”)+”‘”}},
@{Name=”BackupKilobytes”; Expression = {[math]::Round(($EPRestorePoint.GetStorage().Stats.DataSize/1024),1)}},
#@{Name=”TransferedSize in KB”; Expression = {[math]::Round(($_.Progress.TransferedSize/1024),1)}},
@{Name=”NbrOfFiles”; Expression = {$EPJob.ObjectsCount}},
@{Name=”MediaType”; Expression = {“‘D'”}},
#Status,
@{Name=”VendorStatus”; Expression = {switch ($_.Result) {
“Success” {0}
“Failed” {2}
default {1}
}
}},
@{Name=”VendorJobID”; Expression = {“‘”+$_.Id+”‘”}},
#@{Name=”VendorJobID”; Expression = {(“‘”+(Convert-HEXtoDECRes $_.Id)+”‘”) }},
#@{Name=”VendorJobID3″; Expression = { “‘”+$JobIDstring+”‘” }},
@{Name=”VendorPolicyName”; Expression={“‘”+$EPRestorePoint.Name+”‘”}},
@{Name=”JobLevel”; Expression={“‘”+$EPRestorePoint.Type+”‘”}},
#@{Name=”JobLevelSession”;Expression={ $_.JobSess.SessionInfo.SessionAlgorithm}},
@{Name=”TargetName”;Expression={“‘”+$EPRestorePoint.FindBackup().DirPath+”‘”}},
@{Name=”Schedule”; Expression = {“‘”+$EPRestorePoint.FindBackup().TypeToString+”‘”}}#,
# @{Name=”Details”; Expression = {
# If ($tasks.GetDetails() -eq “”){“‘”+($tasks.GetDetails()).Replace(“`n”,” “).Replace(“”,” – “) + ($tasks | Get-VBRTaskSession | %{If ($tasks.GetDetails()){$tasks.Name + “: ” + $tasks.GetDetails()}})+”‘”}
# Else {(“‘”+$tasks.GetDetails()).Replace(“`n”,” “).Replace(“”,” – “)+”‘”}}} #| Format-Table #| ConvertTo-csv | % {$_ -replace ‘”‘,””} #-auto
$outarray = $outarray + $backupEParray
}
foreach ($restores in $RestoreSessionsList) {
[string]$restorestring=””
#[string]$JobIDstring=””
#$RestoreJobIDs=””
#$JobIDInteger=””
$RestoreInfoDetails=””
$restorestring = $restores.Logger.GetLog().UpdatedRecords | where-object {$_.title.Contains(“files to restore”)} | Select-Object title
#$JobIDstring = $restores.ID
#$RestoreJobID = Convert-HEXtoDECRes $JobIDstring
$RestoreInfoDetails = Get-RestoreSize $restorestring
#$RestoreInfoDetails.RestoreSizeKB
#$RestoreInfoDetails.NbrofFiles
$restorearray = $restores | Sort CreationTime | Select @{Name=”VendorName”;Expression={$Vendor}},
@{Name=”ClientName”; Expression = {“‘”+$restores.Info.VmDisplayName+”‘”}},
@{Name=”ClientIPAddress”; Expression = {$nullstrg}},
@{Name=”VendorJobType”; Expression = {“‘RESTORE'”}},
@{Name=”VendorPolicyName”; Expression={“‘”+$restores.Info.JobName+”‘”}},
@{Name=”StartDateString”; Expression = {“‘”+$_.CreationTime.ToString(“yyyy-MM-dd HH:mm:ss”)+”‘”}},
@{Name=”FinishDateString”; Expression = {“‘”+$_.EndTime.ToString(“yyyy-MM-dd HH:mm:ss”)+”‘”}},
@{Name=”BackupKilobytes”; Expression = {$RestoreInfoDetails.RestoreSizeKB}},
@{Name=”NbrOfFiles”; Expression = {$RestoreInfoDetails.NbrofFiles}},
@{Name=”MediaType”; Expression = {“‘D'”}},
#@{Name=”Duration (Mins)”; Expression = {[Math]::Round((New-TimeSpan $_.CreationTime $_.EndTime).TotalMinutes,2)}},
@{Name=”VendorStatus”; Expression = {switch ($_.Info.Result) {
“Success” {0}
“Failed” {2}
default {1}
} }},
@{Name=”VendorJobID”; Expression = {“‘”+$_.Id+”‘”}},
#@{Name=”VendorJobID3″; Expression = {(“‘”+$RestoreJobID+”‘”)}},
#@{Name=”VendorJobID”; Expression = {(“‘”+(Convert-HEXtoDECRes $_.Id)+”‘”)}},
@{Name=”JobLevel”; Expression = {“‘”+$_.JobTypeString+”‘”}},
@{Name=”TargetName”; Expression = {“‘”+$restores.Info.VmDisplayName+”‘”}},
@{Name=”Schedule”; Expression = {“‘”+$_.Info.Initiator.Name+”‘”}},
@{Name=”Details”; Expression = {“‘”+$_.Info.Reason+”‘”}}
#@{Name=”Result”; Expression = {$_.Info.Result}} #| Format-Table -auto
$outarray = $outarray + $restorearray
}
}
# $outarray | ConvertTo-csv -NoTypeInformation | select -Skip 1 |% {$_ -replace ‘”‘,”} #| Out-File $outFile -Encoding utf8
# $outarray | ConvertTo-csv -NoTypeInformation | select -Skip 1 |% {$_ -replace ‘”‘,”} | {switch ($outFile) {“” {} default {Out-File $outFile -Encoding utf8}}}
If ($outFile ) {
$outarray | ConvertTo-csv -NoTypeInformation | select -Skip 1 |% {$_ -replace ‘”‘,”} | Out-File $outFile -Encoding utf8
}
else
{
$outFile
$outarray | ConvertTo-csv -NoTypeInformation | select -Skip 1 |% {$_ -replace ‘”‘,”} #| Out-File $outFile -Encoding utf8
}
Have a look at the value “InsideDir”. It seems to contain your JobID.
Is there a way to encrypt the password in a file and then call that file from the powershell script, instead of stuffing the password in the file in clear text?
I’m guessing you are talking about the email credentials? Certainly can be done, I typically run the script under an account that has privileges to the SMTP server and therefore neither the username or pwd get hard coded.
You should be able to find plenty of examples of what you are looking for on the web.
Actually I was referring to veeam server account and password (and veeam server IP) that is required in the script to access the backups and create the report.
Hmmm, then you have me confused as the script does not hold the VBR u/p – it could, and could save this info to a file, but the assumption is that you would be running the script as a user with permissions, else some code would need to be added.
Hello,
First of all, Thanks a lot for your excelent job !
Would it be possible to add a new feature : could it be possible get an “alert email” eventif report is not generated, or if veeam backup services are not availiable, or any reason preventing report to be received ? I think to manage it not at “Veeam powershell pluging” level, but lower at “windows powershell level”