WindowsBackupReportSetdToMail.ps1


<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 45b85838-9dd0-42ea-8f61-efc1ff0b7ec9
 
.AUTHOR antonov.anton
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
 Windows Backup Report Setd To Mail
 
#>
 

Param()



<# "WindowsBackupReportSetdToMail.ps1" is a Powershell script that analyzes
given Windows Backup storage directory and produces report that
display latest backup sets and their sizes.
.DESCRIPTION
The script is designed to handle a storage that may contain both file
and volume image backup sets, produced by Windows Backup.
 
It can create report in two formats: plain text and HTML and can
either output report text to console or send it via email as message
body. The script locates most recent backup sets for each computer
that did produce backup set(s) to given location and reports them.
Older backup sets will be just not mentioned.
.PARAMETER Root
Denotes the root directory of Windows Backup storage. Can be either
local or UNC path.
.PARAMETER txt
Produce report in plain text format. HTML format will be used if this
parameter is omitted.
.PARAMETER mail
Send produced report to email instead of simple console output. If
invoked - further email-related parameters to be used to specify
details of mailserver and email message. Otherwise, this parameter
will be ignored.
.PARAMETER SmtpSrv
Hostname or IP address of SMTP server to use for email message sending.
.PARAMETER Port
TCP port number of given SMTP server (if it is not standard).
.PARAMETER To
Email addresses of recipient(s). Multiple addresses to be separated
with commas.
.PARAMETER Fm
Sender's email address. It is also used as username for SMTP
authentication.
.PARAMETER Pwd
Password for SMTP authentication.
.PARAMETER Sub
Subject line for email message.
.EXAMPLE
WindowsBackupReportSetdToMail.ps1 -root:\\srv-nas\netbackup
Generates report in HTML format for given UNC path and outputs it to
console.
.EXAMPLE
WindowsBackupReportSetdToMail.ps1 \\srv-nas\netbackup -txt
Generates report in plain text format for given UNC path and outputs
it to console.
.EXAMPLE
WindowsBackupReportSetdToMail.ps1 -root:D:\backup -mail -SmtpSrv:"192.168.1.10" -To:"sysadmin@platano.domain" -Fm:"nas-robot@platano.domain" -Pwd:"Pa$$wOrD" -Sub:"Windows Backup status report"
Generates report in HTML format for given UNC path and outputs it to
console. #>

















Param(
    [Parameter(Mandatory)][string] $Root,
    [switch] $txt=$false,
    [switch] $mail=$false,
    [string] $SmtpSrv,
    [int] $Port=25,
    [string] $To,
    [string] $Fm,
    [string] $Pwd,
    [string] $Sub
)

#------------ FILE backup handling routines -------------------

function Get-MachineListFB ($WinBackupRoot) {
$MachineRoots = @{}
    Get-ChildItem -Path $WinBackupRoot -Recurse -Depth 1 -File -Filter "MediaID.bin" | 
    Where-Object {$_.Directory.FullName -ne $WinBackupRoot} |
    foreach {
            $MachineRoots[$_.Directory.Name]=$_.Directory.FullName
    }
return $MachineRoots
}


function Get-LastFileBackupSet ($MachineRoot) {
$objLB = $null
try {
    $LastWbcat = Get-ChildItem -Path $MachineRoot -Recurse -Depth 2 -File -Filter "GlobalCatalog.wbcat" |
        Where-Object {$_.Directory.Name -eq "Catalogs"} |
        Sort-Object LastWriteTime |
        Select-Object -Last 1 LastWriteTime, Directory, `
            @{Name="Machine";Expression={$_.Directory.Parent.Parent.Name.ToUpper()}}, `
            @{Name="Path";Expression={$_.Directory.Parent.FullName}}, `
            @{Name="Name";Expression={$_.Directory.Parent.Name}}

    $ZIPFiles = (
        Get-ChildItem $LastWbcat.Directory.Parent.FullName -Recurse -Depth 2 -File  -Filter "*.zip" | 
        Select-Object Length | 
        Measure-Object -Property Length -Sum
        )
}
finally
{
    if (($ZIPFiles) -and ($LastWbcat)) {
        $objLB = @{
            Machine = $LastWbcat.Machine
            Path = $LastWbcat.Path
            Name = $LastWbcat.Name
            Updated = $LastWbcat.LastWriteTime
            Size = $ZIPFiles.Sum
        }
    }
}
  return $objLB
}


function Get-LastFileBackupSetSummaryTXTForm ($MachineRoot) {
$ret = ""
$Now = Get-Date
$LastBT = Get-LastFileBackupSet ($MachineRoot)
if ($LastBT) {
    $ret =  "Machine: " + $LastBT.Machine + "`r`nSet name: " + $LastBT.Name + "`r`nLast performed: " + ($Now - $LastBT.Updated).Days + " day(s) ago. (" + $LastBT.Updated + ")`r`nSize: " + ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "MB")
  }
else{
    $ret = "Data retrieving error."
}
return $ret
}


function Get-LastFileBackupSetSummaryTXTRow ($MachineRoot) {
$ret = ""
$Now = Get-Date
$LastBT = Get-LastFileBackupSet ($MachineRoot)
if ($LastBT) {
    $ret = "Machine: " + $LastBT.Machine + "; Set name: " + $LastBT.Name + "; Last performed: " + ($Now - $LastBT.Updated).Days + " day(s) ago. (" + $LastBT.Updated + "); Size: " + ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "MB")
  }
else{
    $ret = "Data retrieving error."
}
return $ret
}


function Get-LastFileBackupSetSummaryHTMLRow ($MachineRoot) {
$ret = ""
$Now = Get-Date
$LastBT = Get-LastFileBackupSet ($MachineRoot)
if ($LastBT) {
    $DaysDiff = ($Now - $LastBT.Updated).Days
    if ($DaysDiff -eq 0) {$ColorCode=""}
    if (($DaysDiff -eq 1) -or ($DaysDiff -eq 2)) {$ColorCode=' style="background-color: #FFFFDD"'}
    if ($DaysDiff -gt 2) {$ColorCode=' style="background-color: #FFAAAA"'}
    $ret = "<tr><td>" + $LastBT.Machine + "</td><td>" + $LastBT.Name + "</td><td align=right" + $ColorCode + ">" + $DaysDiff + " day(s)</td><td>" + $LastBT.Updated + "</td><td align=right>" + ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "MB") + "</td></tr>"
  }
else{
    $ret = "<tr><td>Data retrieving error.</td></tr>"
}
return $ret
}


function Get-LastFileBackupDatesTXT ($WinBackupRoot) {
$table="File backup:`r`n"
$MachineRoots = Get-MachineListFB ($WinBackupRoot)
foreach ($machine in $MachineRoots.Keys) {
    $line = Get-LastFileBackupSetSummaryTXTRow($MachineRoots[$machine])
    $table+= -join($line, "`r`n")
    }
return $table
}


function Get-LastFileBackupDatesHTML ($WinBackupRoot) {
$table+='<h4>File backup:'+"</h4>`n"
$table+="<table border=1>`n"
$table+='<tr><td><h4>Machine</h4></td><td><h4>Latest backup set dir</h4></td><td><h4>Age</h4></td><td><h4>Updated</h4></td><td><h4>Size</h4></td></tr>'+"`n"
$MachineRoots = Get-MachineListFB ($WinBackupRoot)
foreach ($machine in $MachineRoots.Keys) {
    $line = Get-LastFileBackupSetSummaryHTMLRow($MachineRoots[$machine])
    $table+= -join($line, "`n")
    }
$table+= "</table>`n"
return $table
}


#------------ IMAGE backup handling routines -------------------

function Get-MachineListIB ($WinBackupRoot) {
$MachineRoots = @{}
$ImageBackupRoot = $WinBackupRoot+"\WindowsImageBackup"
    Get-ChildItem -Path $ImageBackupRoot -Recurse -Depth 1 -File -Filter "MediaID" | 
    foreach {
        $MachineRoots[$_.Directory.Name]=$_.Directory.FullName
        }
return $MachineRoots
}


function Get-LastImageBackupSet ($MachineRoot) {
$objLB = $null
try {
    $LastBSXML = Get-ChildItem -Path $MachineRoot -Recurse -Depth 1 -File -Filter "BackupSpecs.xml" | 
        Sort-Object LastWriteTime |
        Select-Object -Last 1 LastWriteTime, Directory, `
            @{Name="Machine";Expression={$_.Directory.Parent.Name.ToUpper()}}, `
            @{Name="Path";Expression={$_.Directory.FullName}}, `
            @{Name="Name";Expression={$_.Directory.Name}}
    $VHDFiles = (
        Get-ChildItem $LastBSXML.Directory.FullName -File -Filter "*.vhd" | 
        Select-Object Length | 
        Measure-Object -property length -sum -ErrorAction SilentlyContinue)
}
finally
{
  if (($VHDFiles) -and ($LastBSXML)) {
      $objLB = @{
          Machine = $LastBSXML.Machine
          Path = $LastBSXML.Path
          Name = $LastBSXML.Name
          Updated = $LastBSXML.LastWriteTime
          Size = $VHDFiles.Sum
      }
  }
}
  return $objLB
}


function Get-LastImageBackupSetSummaryTXTForm ($MachineRoot) {
$ret = ""
$Now = Get-Date
$LastBT = Get-LastImageBackupSet ($MachineRoot)
if ($LastBT) {
    $ret =  "Machine: " + $LastBT.Machine + "`nSet name: " + $LastBT.Name + "`nLast performed: " + ($Now - $LastBT.Updated).Days + " day(s) ago. (" + $LastBT.Updated + ")`nSize: " + ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "MB`r`n")
  }
else{
    $ret = "Data retrieving error."
}
return $ret
}


function Get-LastImageBackupSetSummaryTXTRow ($MachineRoot) {
$ret = ""
$Now = Get-Date
$LastBT = Get-LastImageBackupSet ($MachineRoot)
if ($LastBT) {
    $ret = "Machine: " + $LastBT.Machine + "; Set name: " + $LastBT.Name + "; Last performed: " + ($Now - $LastBT.Updated).Days + " day(s) ago. (" + $LastBT.Updated + "); Size: " + ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "MB")
  }
else{
    $ret = "Data retrieving error."
}
return $ret
}


function Get-LastImageBackupSetSummaryHTMLRow ($MachineRoot) {
$ret = ""
$Now = Get-Date
$LastBT = Get-LastImageBackupSet ($MachineRoot)
if ($LastBT) {
    $DaysDiff = ($Now - $LastBT.Updated).Days
    if ($DaysDiff -eq 0) {$ColorCode=""}
    if (($DaysDiff -eq 1) -or ($DaysDiff -eq 2)) {$ColorCode=' style="background-color: #FFFFDD"'}
    if ($DaysDiff -gt 2) {$ColorCode=' style="background-color: #FFAAAA"'}
    $ret = "<tr><td>" + $LastBT.Machine + "</td><td>" + $LastBT.Name + "</td><td align=right" + $ColorCode + ">" + $DaysDiff + " day(s)</td><td>" + $LastBT.Updated + "</td><td align=right>" + ('{0:0} {1}' -f ($LastBT.Size/1024/1024), "MB") + "</td></tr>"
  }
else{
    $ret = "<tr><td>Data retrieving error.</td></tr>"
}
return $ret
}


function Get-LastImageBackupDatesTXT ($WinBackupRoot) {
$table="Image backup:`r`n"
$MachineRoots = Get-MachineListIB ($WinBackupRoot)
foreach ($machine in $MachineRoots.Keys) {
    $line = Get-LastImageBackupSetSummaryTXTRow($MachineRoots[$machine])
    $table+= -join($line, "`r`n")
    }
return $table
}


function Get-LastImageBackupDatesHTML ($WinBackupRoot) {
$table+='<h4>Volume image backup:'+"</h4>`n"

$table+="<table border=1>`n"
$table+='<tr><td><h4>Machine</h4></td><td><h4>Latest backup set dir</h4></td><td><h4>Age</h4></td><td><h4>Updated</h4></td><td><h4>Size</h4></td></tr>'+"`n"
$MachineRoots = Get-MachineListIB ($WinBackupRoot)
foreach ($machine in $MachineRoots.Keys) {
    $line = Get-LastImageBackupSetSummaryHTMLRow($MachineRoots[$machine])
    $table+= -join($line, "`n")
    }
$table+= "</table>`n"

return $table
}


#------------ Common routines -------------------

function Get-LastWinBackupDatesHTML ($WinBackupRoot) {
$Now = Get-Date
$table='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'+"`n"
$table+='<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Backup volumes at "'+$WinBackupRoot+'"</title></head><body>'+"`n"
$table+='<h3>Backup volumes at "'+$WinBackupRoot+'"'+"</h3>`n"
$table+='<h3>Generated: '+$Now+"</h3>`n"
$table+= Get-LastFileBackupDatesHTML ($WinBackupRoot)
$table+= Get-LastImageBackupDatesHTML ($WinBackupRoot)
$table+= "</body>`n</html>"
return $table
}

function Get-LastWinBackupDatesTXT ($WinBackupRoot) {
$Now = Get-Date
$table='Backup volumes at "'+$WinBackupRoot+'"'+"`r`n"
$table+='Generated: '+$Now+"`r`n`r`n"
$table+= Get-LastFileBackupDatesTXT ($WinBackupRoot)
$table+= "`r`n"
$table+= Get-LastImageBackupDatesTXT ($WinBackupRoot)
return $table
}


function Send-Email-Report ($SendInfo, $TXTonly=$false){
$Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $SendInfo.Username, $SendInfo.SecurePassword
if ($TXTonly) {
    Send-MailMessage -To $SendInfo.To -From $SendInfo.From -Subject $SendInfo.Subject -Body $SendInfo.MsgBody -SmtpServer $SendInfo.SmtpServer -Credential $Credential -Port $SendInfo.SmtpPort -Encoding UTF8
    }
else
    {
    Send-MailMessage -To $SendInfo.To -From $SendInfo.From -Subject $SendInfo.Subject -BodyAsHtml $SendInfo.MsgBody -SmtpServer $SendInfo.SmtpServer -Credential $Credential -Port $SendInfo.SmtpPort
    }
}


#------------ MAIN ROUTINE -------------------

if ($txt) {
    $Ret = Get-LastWinBackupDatesTXT ($Root)
    }
else {
    $Ret = Get-LastWinBackupDatesHTML ($Root)
    }

if ($mail) {
    if (($SmtpSrv) -and ($Port) -and ($To) -and ($Fm) -and ($Pwd) -and ($Sub) -and ($Ret)) {
            $objArgs = @{
                SmtpServer = $SmtpSrv
                SmtpPort = $Port
                To = $To.Split(',')
                From = $Fm
                Username = $Fm
                SecurePassword = ConvertTo-SecureString -String $Pwd -AsPlainText -Force
                Subject = $Sub
                MsgBody = $Ret
            }
            Send-Email-Report ($objArgs, $txt)
        }
    else {
        Write-Host $Ret
        }
    }
else {
    Write-Host $Ret
    }