none
Need a Script to email DPM Protection Group Status reports in Formatted HTML Output. RRS feed

  • Question

  • Need a Script to email DPM 2012 Protection Group Status reports in Formatted HTML Output.
    Tuesday, January 14, 2014 4:21 PM

All replies

  • This script was created to keep track of all the DPM 2012 Servers we have and to track specific protection groups. There are only a few things to change to tailor this to your environment. Let me know if this helps you any, thanks.

    1) Change the DPM server names ---
    $dpmservers = "DPMSERVERNAMEGOESHERE","DPMSERVERNAME2"

    2)Change the domain name in the loop ---                                                                                                 $computer = $ds.productionservername.toupper().replace(".DOMAINNAMEGOESHERE.COM","")

    3) Optional you can change this to any day of week and track a specific protection group.                   if((($dayofweek -eq "Sunday")-or($dayofweek -eq "Monday")-or($dayofweek -eq "Tuesday"))-and(($pgname -eq "SIGNIFICANT PROTECTION GROUP NAME")))

    4) Anywhere it states PROTECTION GROUP NAME is changeable and can be added to to track

    5) Bottom of script is where you change the SMTP and email properties.

    ##########################################################
    #
    # Recovery Point Status Script
    #
    # This script will take one variable, DPM server name
    # and get the latested recovery point for each
    # protection group. This information will be formatted
    # into HTML and emailed to the group specified below
    #
    # Taylor Morrison - 2/14/2014
    #
    ##########################################################

    $erroractionpreference = "SilentlyContinue"

    # Ensure the DPM Powershell snapin is enabled
    Import-Module DataProtectionManager

    $dpmservers = "DPMSERVERNAMEGOESHERE","DPMSERVERNAME2"

    # Begin creation of the HTML for the email
    $body = "<head>"
    $body = $body + "<style>"
    $body = $body + "BODY{background-color:white;}"
    $body = $body + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
    $body = $body + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:grey}"
    $body = $body + "TD{border-width: 1px;padding: 4px;border-style: solid;border-color: black;background-color:white}"
    $body = $body + "td.green{background-color: green; color: black;}"
    $body = $body + "td.gray{background-color: gray; color: black;}"
    $body = $body + "td.silver{background-color: silver; color: black;}"
    $body = $body + "td.fsdata{background-color: #87AFC7; color: black;}"
    $body = $body + "td.red{background-color: red; color: black;}"
    $body = $body + "</style>"
    $body = $body + "</head>"
    $body = $body + "<body>"
    #$body = $body + "<font size=" + '"2"' + " face=" + '"arial black"' + ">"
    #$body = $body + "<H4 align=" + '"center"' + ">DPM Data Backup Report - $(Get-Date -F MM/dd/yy)</H4>"
    #$body = $body + "</font>"
    $body = $body + "<table align=" + '"center"' + ">"
    $body = $body + "<colgroup>"
    $body = $body + "<col>"
    $body = $body + "<col>"
    $body = $body + "<col>"
    $body = $body + "<col>"
    $body = $body + "</colgroup>"

    foreach($dpmserver in $dpmservers){
        $dpmserver = $dpmserver.toupper()
            
        if($dpmserver -eq "NONE"){
            $body = $body + "<font size=" + '"2"' + " face=" + '"arial"' + ">"
            $body = $body + "<tr><td align=" + '"center"' + ";colspan=" + '"4"' + ";class=" + '"gray"' + ">$dpmserver - Significant Data (Off-Site)</td></tr>"
            $body = $body + "</font>"
        }
        else{
            $body = $body + "<font size=" + '"2"' + " face=" + '"arial"' + ">"
            $body = $body + "<tr><td align=" + '"center"' + ";colspan=" + '"4"' + ";class=" + '"gray"' + ">$dpmserver</td></tr>"
            $body = $body + "</font>"
        }        

        $body = $body + "<font size=" + '"1"' + " face=" + '"arial"' + ">"
        $body = $body + "<tr><td align=" + '"center"' + "class=" + '"silver"' + ">Protection Group</td><td align=" + '"center"' + "class=" + '"silver"' + ">Computer</td><td align=" + '"center"' + "class=" +

    '"silver"' + ">Object</td><td align=" + '"center"' + "class=" + '"silver"' + ">Last RP</td></tr>"
        $body = $body + "</font>"
        $body = $body + "<font size=" + '"1"' + " face=" + '"arial"' + ">"

        # Create list of protection groups for this DPM server
        $pglist = get-protectiongroup $dpmserver | sort-object friendlyname

        # Loop through the protection groups to get the current status and update info in the HTML
        foreach($pg in $pglist){
            $pgname = $pg.friendlyname.toupper()
            $dslist = get-datasource $pg

            foreach($ds in $dslist){
                $ds.latestrecoverypoint
                start-sleep -s 5
                $name = $ds.name
                $computer = $ds.productionservername.toupper().replace(".DOMAINNAMEGOESHERE.COM","")
                $rprt = [datetime]$ds.latestrecoverypoint
                $rprt
                $datedif = $(get-date) - $rprt
                $days = $datedif.days * 24
                $time = $days+$datedif.hours

                if((($dayofweek -eq "Sunday")-or($dayofweek -eq "Monday")-or($dayofweek -eq "Tuesday"))-and(($pgname -eq "SIGNIFICANT PROTECTION GROUP NAME"))){}
                else{

                    if($time -gt 24){
                        if(($pgname -eq "PROTECTION GROUP NAME")-or($pgname -eq "PROTECTION GROUP NAME2")){
                            $body = $body + "<tr><td align=" + '"center"' + ";class=" + '"fsdata"' + ">$pgname</td><td align=" + '"center"' + ";class=" + '"fsdata"' + ">$computer</td><td

    align=" + '"center"' + ";class=" + '"fsdata"' + ">$name</td><td align=" + '"center"' + "class=" + '"red">' + "$rprt</td></tr>"
                        }
                        
                        else{
                            $body = $body + "<tr><td align=" + '"center"' + ">$pgname</td><td align=" + '"center"' + ">$computer</td><td align=" + '"center"' + ">$name</td><td align=" +

    '"center"' + "class=" + '"red">' + "$rprt</td></tr>"
                        }
                    }
                    else{
                        if(($pgname -eq "PROTECTION GROUP NAME")-or($pgname -eq "PROTECTION GROUP NAME2")){
                            $body = $body + "<tr><td align=" + '"center"' + ";class=" + '"fsdata"' + ">$pgname</td><td align=" + '"center"' + ";class=" + '"SIG DATA"' + ">$computer</td><td

    align=" + '"center"' + ";class=" + '"fsdata"' + ">$name</td><td align=" + '"center"' + "class=" + '"green">' + "$rprt</td></tr>"
                        }
                        #elseif($pgname -eq "SIGNIFICANT DATA"){}
                        else{
                            $body = $body + "<tr><td align=" + '"center"' + ">$pgname</td><td align=" + '"center"' + ">$computer</td><td align=" + '"center"' + ">$name</td><td align=" +

    '"center"' + "class=" + '"green">' + "$rprt</td></tr>"
                        }
                    }
                }
            }
        }

        

    # Complete HTML formatting
    $body = $body + "</font>"
    disconnect-dpmserver
    }

    # Complete HTML formatting
    $body = $body + "<font size=" + '"2"' + " face=" + '"arial"' + ">"
    $body = $body + "<tr><td align=" + '"center"' + ";colspan=" + '"4"' + ";class=" + '"fsdata"' + ">Items highlighted in this color represent - SIGNIFICANT DATA</td></tr>"
    $body = $body + "</font>"
    $body = $body + "</body>"

    # Create and send email containing the HTML
    $smtpserver = "smtp.DOMAIN.com"
    $mailer = new-object Net.Mail.SMTPclient($smtpserver)
    $from = "dpmreporting@DOMAIN.COM"
    $to = "EMAIL@DOMAIN.COM"
    $subject = "DPM 2012 Data Backup Report - $(Get-Date -F MM/dd/yy)"
    $msg = new-object Net.Mail.MailMessage($from,$to,$subject,$body)
    $msg.IsBodyHTML = $true
    $mailer.send($msg)

    Tuesday, February 11, 2014 4:43 PM
  • #FindRecoveryPoints.ps1
     #This script finds the newest and oldest recovery points from
     #your dpm server and writes them to an html table
     
     
     # Put all your dpm server names in the array. If there is only 1, that is fine.
     $dpmservers = @("","","")
     
     # The date is used to find recovery points that are too old, and to generate a file #name.
     $date = get-date
     $filedate = get-date -uformat '%m-%d-%Y-%H%M%S'
     $filename = "C:\script\reports\DPMRecoveryPoints"+ $filedate + ".htm"
     
     
     $emailto = ””
     
     $emailfrom = ”” 
     
     $hname = ""
     
     
     $backuplocation = "C:\script\reports\" 
     new-item $backuplocation  -type directory -force
     $backuplog="$backuplocation"+(get-date -f MM-dd-yyyy)+"-backup-$hname.log" 
     $emailserver="" 
     
     #    Dotsource in the functions you need. 
            if (!(Get-PSSnapin |Where-Object {$_.Name -eq "Microsoft.DataProtectionManager.PowerShell"})) 
            { 
                try 
                { 
                    Write-Verbose "Adding DPM Snap-in" 
                    Add-PSSnapin -Name "Microsoft.DataProtectionManager.PowerShell" 
                    } 
                catch 
                { 
                    Return $Error[0].Exception.InnerException.Message.ToString().Trim() 
                    } 
                }
     
     function SendEmail($To, $From, $Subject, $Body, $attachment, $smtpServer) 
    { 
            Send-MailMessage -To $To -Subject $Subject -From $From -Body $Body -Attachment $attachment -SmtpServer $smtpServer 
    } 
      
    Function InitializeDatasourceProperties ($datasources)
     {
     $Eventcount = 0
     For($i = 0;$i -lt $datasources.count;$i++)
     {
     [void](Register-ObjectEvent $datasources[$i] -EventName DataSourceChangedEvent -SourceIdentifier "DPMExtractEvent$i" -Action{$Eventcount++})
     }
     $datasources | select LatestRecoveryPoint > $null
     $begin = get-date
     While (((Get-Date).subtract($begin).seconds -lt 10) -and ($Eventcount -lt $datasources.count) ) {sleep -Milliseconds 250}
     Unregister-Event -SourceIdentifier DPMExtractEvent* -Confirm:$false
     }
     
    #Writes name and recovery point info for current iteration of $ds into HTML table. Newest recovery points not in the last 24 hours are red.
     #If there are no recovery points(1/1/0001), the table reads "Never" in red.
     Function WriteTableRowToFile($ThisDatasource, $dpmserver)
     {
     $rpLatest = $ThisDatasource.LatestRecoveryPoint
     $rpOldest = $ThisDatasource.OldestRecoveryPoint
     
    "<tr><td>" | Out-File $filename -Append -Confirm:$false
     $ThisDatasource.ProductionServerName | Out-File $filename -Append -Confirm:$false
     "</td><td>" | Out-File $filename -Append -Confirm:$false
     $ThisDatasource.Name | Out-File $filename -Append -Confirm:$false
     If($rpLatest -lt $date.AddHours(-24)){
     If($rpLatest.ToShortDateString() -eq "1/1/0001"){
     "</td><td><b><font style=`"color: #FF0000;`">Never</font></b>" | Out-File $filename -Append -Confirm:$false
     }
     Else{
     "</td><td><b><font style=`"color: #FF0000;`">" | Out-File $filename -Append -Confirm:$false
     $rpLatest.ToShortDateString() | Out-File $filename -Append -Confirm:$false
     "</font></b>" | Out-File $filename -Append -Confirm:$false
     }
     }
     If($rpLatest -ge $date.AddHours(-24)){
     "</td><td>" | Out-File $filename -Append -Confirm:$false
     $rpLatest.ToShortDateString() | Out-File $filename -Append -Confirm:$false
     "</td>" | Out-File $filename -Append -Confirm:$false
     }
     
    If($rpOldest.ToShortDateString() -eq "1/1/0001"){
     "<td><b><font style=`"color: #FF0000;`">Never</font></b></td><td>" | Out-File $filename -Append -Confirm:$false
     }
     Else{
     "<td>" | Out-File $filename -Append -Confirm:$false
     $rpOldest.ToShortDateString()| Out-File $filename -Append -Confirm:$false
     "</td><td>" | Out-File $filename -Append -Confirm:$false
     }
     ($rpLatest - $rpOldest).Days | Out-File $filename -Append -Confirm:$false
     "</td><td>" | Out-File $filename -Append -Confirm:$false
     
    $dpmServer | out-file $filename -append -confirm:$false
     "</td></tr>" | Out-File $filename -Append -Confirm:$false
     }
     
    ##Main#
     
    ## HTML table created
     "<html><caption><font style=`"color: #FF0000;`"><b>Red</b></font> = not backed up in the last 24 hours, or has <font style=`"color: #FF0000;`">
     <b>Never</b></font> been backed up</caption><table border =`"1`" style=`"text-align:center`" cellpadding=`"5`"><th style=`"color:#6698FF`">
     <big>DPM Backups</big></th><body><tr><th>Protection Member</th><th>Datasource</th><th>Newest Backup</th><th>Oldest Backup</th><th># of Days</th>
     <th>DPM Server</th></tr>" | Out-File $filename -Confirm:$false
     
    Write-Host "Generating Protection Group Report" 
     #Disconnect-DPMserver = clear cache, this makes sure that selecting LatestRecoveryPoint in the InitializeDataSourceProperties is an event,
     #thus confirming that all the recovery points are retrieved before the script moves any further
     Disconnect-DPMserver
     #Find all datasources within each protection group
     Write-Host "Locating Datasources" 
     foreach ($dpmserver in $dpmservers){
     $dsarray = @(Get-ProtectionGroup -DPMServer $dpmserver | foreach {Get-Datasource $_}) | Sort-Object ProtectionGroup, ProductionServerName
     Write-Host " Complete" -ForegroundColor Green 
     Write-Host "Finding Recovery Points"
     InitializeDatasourceProperties $dsarray
     Write-Host " Complete" -ForegroundColor Green
     Write-Host "Writing to File"
     For($i = 0;$i -lt $dsarray.count;$i++)
     {
     WriteTableRowToFile $dsarray[$i] $dpmserver
     }
     Disconnect-DPMserver
     }
     Write-Host " Complete" -ForegroundColor Green 
     Write-Host "The report has been saved to"$filename 
     "</body></html>" | Out-File $filename -Append -Confirm:$false
     
     SendEmail -To "$emailto" -From "$emailfrom" -Subject "Report $hname ok" -Body "The report has succeeded!" -attachment "$filename" -smtpServer "$emailserver" 
     


    Have a nice day !!!

    Wednesday, February 12, 2014 8:13 AM
    Moderator
  • Get-DPMRecoveryPointReport.ps1

    [CmdletBinding()]
    Param
        (
            [Parameter(Mandatory=$true)]$DPMServerName = 'dpm',
            [Parameter(Mandatory=$true)]$ProtectedComputer
        )
    Begin
        {
            $ScriptName = $MyInvocation.MyCommand.ToString()
            $LogName = "Application"
            $ScriptPath = $MyInvocation.MyCommand.Path
            $Username = $env:USERDOMAIN + "\" + $env:USERNAME
     
            New-EventLog -Source $ScriptName -LogName $LogName -ErrorAction SilentlyContinue
     
            $Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nStarted: " + (Get-Date).toString()
            Write-EventLog -LogName $LogName -Source $ScriptName -EventID "104" -EntryType "Information" -Message $Message
     
            #	Dotsource in the functions you need.
            if (!(Get-PSSnapin |Where-Object {$_.Name -eq "Microsoft.DataProtectionManager.PowerShell"}))
            {
                try
                {
                    Write-Verbose "Adding DPM Snap-in"
                    Add-PSSnapin -Name "Microsoft.DataProtectionManager.PowerShell"
                    }
                catch
                {
                    Return $Error[0].Exception.InnerException.Message.ToString().Trim()
                    }
                }
    
            Write-Verbose "Get the ProductionServer object that matches the ProtectedComputer, that actually has a DataSource."
            $ProdServer =  Get-ProductionServer -DPMServerName $DPMServerName `
                |Where-Object {$_.MachineName -eq $ProtectedComputer} `
                |Where-Object {$_.IsHavingDataSourcesProtected -eq $True}
            
            Write-Verbose "Get a list of the DataSources available on the ProductionServer"
            $DataSources = Get-Datasource -ProductionServer $ProdServer
    
            $Report = @()
            }
    Process
        {
            Write-Verbose "Loop through each available DataSource"
            foreach ($DataSource in $DataSources)
            {
                Write-Verbose "Get a list of RecoveryPoints for each DataSource"
                $RecoveryPoints = Get-RecoveryPoint -Datasource $DataSource
                
                Write-Verbose "Loop through each available RecoveryPoint"
                foreach ($RecoveryPoint in $RecoveryPoints)
                {
                    Write-Verbose "Check if the RecoveryPoint is not empty"
                    if (!($RecoveryPoint -eq $null))
                    {
                        Write-Verbose "Pulling UserFriendlyName, RepresentedPointIntTime and Size from this RecoveryPoint"
                        $LineItem = New-Object -TypeName PSobject -Property @{
                            RecoveryPoint = $RecoveryPoint.UserFriendlyName;
                            DateTime = $RecoveryPoint.RepresentedPointInTime;
                            Size = $RecoveryPoint.Size /1gb
                            DataSource = "$($RecoveryPoint.DataSource.Name) on $($RecoveryPoint.DataSource.ProductionServerName)"
                            Server = $RecoveryPoint.DataSource.ProductionServerName
                            Location = $RecoveryPoint.DataLocation
                            }
                        $Report += $LineItem
                        }
                    }
                }
            }
    End
        {
            $Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nFinished: " + (Get-Date).toString()
            Write-EventLog -LogName $LogName -Source $ScriptName -EventID "104" -EntryType "Information" -Message $Message	
            Return $Report
            }


    Have a nice day !!!

    Wednesday, February 12, 2014 8:14 AM
    Moderator
  • Thanks Morrison,

    It works for me on my testing DPM, there I have only 2 Protection groups with 8 datasources. But this script is taking more than half an hour on my production DPM, as its counting dates and days. I didnt understand why these days parameter are added to script. Can be it works without these? I just want to fetch current state of each datasource weather it is valid or invalid.

    This is how its running now.......
    • Edited by V Jay Rana Tuesday, February 25, 2014 2:49 PM
    Tuesday, February 25, 2014 2:26 PM