PRTG Daily Email Powershell Script

So I don't write much powershell but recently I needed a way to send daily emails out of PRTG. Thanks Paessler which has kept it simple with their PRTG monitoring system as the hardest part of this script was getting the data in HTML, remember I don't write much powershell. ;) If you have not used PRTG before check it out if you need some alerting in your environment. Personally this is one of my favorite systems for just monitoring because a lot of other monitoring systems include everything but the kitchen sink and reality we just need to know what's up and what's down. This script grabs an XML file that PRTG builds and saves it as "table.xml" I have the script check if there are any sensors in trouble if not send an email. If PRTG is reporting a sensor or sensors that are in trouble this scripts builds an HTML document with a table and list the sensors in trouble highlighting the status column with the appropriate color and sends an email.

Thanks goes to Martin Pugh who has provided the set-cellcolor function. :)

  1# PRTG EMAIL ACTIVE ALARMS POWERSHELL SCRIPT.
  2# USE TASK SCHEDULER TO RUN THIS SCRIPT. 
  3# Load up the function "Set-CellColor" thanks to Martin Pugh <img draggable="false" role="img" class="emoji" alt="🙂" src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/1f642.svg">
  4Function Set-CellColor
  5{   <#
  6    .SYNOPSIS
  7        Function that allows you to set individual cell colors in an HTML table
  8    .DESCRIPTION
  9        To be used inconjunction with ConvertTo-HTML this simple function allows you
 10        to set particular colors for cells in an HTML table.  You provide the criteria
 11        the script uses to make the determination if a cell should be a particular 
 12        color (property -gt 5, property -like "*Apple*", etc).
 13         
 14        You can add the function to your scripts, dot source it to load into your current
 15        PowerShell session or add it to your $Profile so it is always available.
 16         
 17        To dot source:
 18            .".\Set-CellColor.ps1"
 19             
 20    .PARAMETER Property
 21        Property, or column that you will be keying on.  
 22    .PARAMETER Color
 23        Name or 6-digit hex value of the color you want the cell to be
 24    .PARAMETER InputObject
 25        HTML you want the script to process.  This can be entered directly into the
 26        parameter or piped to the function.
 27    .PARAMETER Filter
 28        Specifies a query to determine if a cell should have its color changed.  $true
 29        results will make the color change while $false result will return nothing.
 30         
 31        Syntax
 32        <Property Name> <Operator> <Value>
 33         
 34        <Property Name>::= the same as $Property.  This must match exactly
 35        <Operator>::= "-eq" | "-le" | "-ge" | "-ne" | "-lt" | "-gt"| "-approx" | "-like" | "-notlike" 
 36            <JoinOperator> ::= "-and" | "-or"
 37            <NotOperator> ::= "-not"
 38         
 39        The script first attempts to convert the cell to a number, and if it fails it will
 40        cast it as a string.  So 40 will be a number and you can use -lt, -gt, etc.  But 40%
 41        would be cast as a string so you could only use -eq, -ne, -like, etc.  
 42    .PARAMETER Row
 43        Instructs the script to change the entire row to the specified color instead of the individual cell.
 44    .INPUTS
 45        HTML with table
 46    .OUTPUTS
 47        HTML
 48    .EXAMPLE
 49        get-process | convertto-html | set-cellcolor -Propety cpu -Color red -Filter "cpu -gt 1000" | out-file c:\test\get-process.html
 50 
 51        Assuming Set-CellColor has been dot sourced, run Get-Process and convert to HTML.  
 52        Then change the CPU cell to red only if the CPU field is greater than 1000.
 53         
 54    .EXAMPLE
 55        get-process | convertto-html | set-cellcolor cpu red -filter "cpu -gt 1000 -and cpu -lt 2000" | out-file c:\test\get-process.html
 56         
 57        Same as Example 1, but now we will only turn a cell red if CPU is greater than 100 
 58        but less than 2000.
 59         
 60    .EXAMPLE
 61        $HTML = $Data | sort server | ConvertTo-html -head $header | Set-CellColor cookedvalue red -Filter "cookedvalue -gt 1"
 62        PS C:\> $HTML = $HTML | Set-CellColor Server green -Filter "server -eq 'dc2'"
 63        PS C:\> $HTML | Set-CellColor Path Yellow -Filter "Path -like ""*memory*""" | Out-File c:\Test\colortest.html
 64         
 65        Takes a collection of objects in $Data, sorts on the property Server and converts to HTML.  From there 
 66        we set the "CookedValue" property to red if it's greater then 1.  We then send the HTML through Set-CellColor
 67        again, this time setting the Server cell to green if it's "dc2".  One more time through Set-CellColor
 68        turns the Path cell to Yellow if it contains the word "memory" in it.
 69         
 70    .EXAMPLE
 71        $HTML = $Data | sort server | ConvertTo-html -head $header | Set-CellColor cookedvalue red -Filter "cookedvalue -gt 1" -Row
 72         
 73        Now, if the cookedvalue property is greater than 1 the function will highlight the entire row red.
 74         
 75    .NOTES
 76        Author:             Martin Pugh
 77        Twitter:            @thesurlyadm1n
 78        Spiceworks:         Martin9700
 79        Blog:               www.thesurlyadmin.com
 80           
 81        Changelog:
 82            1.5             Added ability to set row color with -Row switch instead of the individual cell
 83            1.03            Added error message in case the $Property field cannot be found in the table header
 84            1.02            Added some additional text to help.  Added some error trapping around $Filter
 85                            creation.
 86            1.01            Added verbose output
 87            1.0             Initial Release
 88    .LINK
 89        http://community.spiceworks.com/scripts/show/2450-change-cell-color-in-html-table-with-powershell-set-cellcolor
 90    #>
 91 
 92    [CmdletBinding()]
 93    Param (
 94        [Parameter(Mandatory,Position=0)]
 95        [string]$Property,
 96        [Parameter(Mandatory,Position=1)]
 97        [string]$Color,
 98        [Parameter(Mandatory,ValueFromPipeline)]
 99        [Object[]]$InputObject,
100        [Parameter(Mandatory)]
101        [string]$Filter,
102        [switch]$Row
103    )
104     
105    Begin {
106        Write-Verbose "$(Get-Date): Function Set-CellColor begins"
107        If ($Filter)
108        {   If ($Filter.ToUpper().IndexOf($Property.ToUpper()) -ge 0)
109            {   $Filter = $Filter.ToUpper().Replace($Property.ToUpper(),"`$Value")
110                Try {
111                    [scriptblock]$Filter = [scriptblock]::Create($Filter)
112                }
113                Catch {
114                    Write-Warning "$(Get-Date): ""$Filter"" caused an error, stopping script!"
115                    Write-Warning $Error[0]
116                    Exit
117                }
118            }
119            Else
120            {   Write-Warning "Could not locate $Property in the Filter, which is required.  Filter: $Filter"
121                Exit
122            }
123        }
124    }
125     
126    Process {
127        ForEach ($Line in $InputObject)
128        {   If ($Line.IndexOf("<tr><th") -ge 0)
129            {   Write-Verbose "$(Get-Date): Processing headers..."
130                $Search = $Line | Select-String -Pattern '<th ?[a-z\-:;"=]*>(.*?)<\/th>' -AllMatches
131                $Index = 0
132                ForEach ($Match in $Search.Matches)
133                {   If ($Match.Groups[1].Value -eq $Property)
134                    {   Break
135                    }
136                    $Index ++
137                }
138                If ($Index -eq $Search.Matches.Count)
139                {   Write-Warning "$(Get-Date): Unable to locate property: $Property in table header"
140                    Exit
141                }
142                Write-Verbose "$(Get-Date): $Property column found at index: $Index"
143            }
144            If ($Line -match "<tr( style=""background-color:.+?"")?><td")
145            {   $Search = $Line | Select-String -Pattern '<td ?[a-z\-:;"=]*>(.*?)<\/td>' -AllMatches
146                $Value = $Search.Matches[$Index].Groups[1].Value -as [double]
147                If (-not $Value)
148                {   $Value = $Search.Matches[$Index].Groups[1].Value
149                }
150                If (Invoke-Command $Filter)
151                {   If ($Row)
152                    {   Write-Verbose "$(Get-Date): Criteria met!  Changing row to $Color..."
153                        If ($Line -match "<tr style=""background-color:(.+?)"">")
154                        {   $Line = $Line -replace "<tr style=""background-color:$($Matches[1])","<tr style=""background-color:$Color"
155                        }
156                        Else
157                        {   $Line = $Line.Replace("<tr>","<tr style=""background-color:$Color"">")
158                        }
159                    }
160                    Else
161                    {   Write-Verbose "$(Get-Date): Criteria met!  Changing cell to $Color..."
162                        $Line = $Line.Replace($Search.Matches[$Index].Value,"<td style=""background-color:$Color"">$Value</td>")
163                    }
164                }
165            }
166            Write-Output $Line
167        }
168    }
169     
170    End {
171        Write-Verbose "$(Get-Date): Function Set-CellColor completed"
172    }
173}
174# Load up the variables, feel free to edit below like what is your email server?
175$smtp = "mailserver.example.com"
176# Who is this email going to?
177$to = "Mr. Joe <joe@example.com>"
178# Carbon Copy anyone?
179$cc = "Mr. Admin <admin@example.com>"
180$from = "PRTG Network Monitor <PRTG@example.com>"
181$subject = "PRTG Checks"
182$time = Get-Date
183# Get a table ready in HTML just in case we have alerts in PRTG.
184$a = "<style>"
185$a = $a + "BODY{background-color:White;}"
186$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
187$a = $a + "TH{Font-family: Courier; color: white; border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color:black}"
188$a = $a + "TD{Font-family: Courier; border-width: 1px;padding: 3px;border-style: solid;border-color:}"
189$a = $a + "</style>"
190# Write out something in HTML in case we have alerts in PRTG.
191$b = "<H2>PRTG Alerts</H2>"
192$b = $b + "<p>Houston, we have a problem so please reference the chart below.</p>"
193$b = $b + "<p>System Generated at $time.</p>"
194# Write out something in HTML in case no alerts are active. 
195$c = "<H2>PRTG Alerts </H2>"
196$c = $c + "<p>No alerts being reported.</p>"
197$c = $c + "<p>System Generated at $time.</p>"
198# URL to your PRTG server you will need to reference a local user account and password that has access to PRTG. See the end of the URL. 
199$url = "https://prtg.example.com/api/table.xml?content=sensors&columns=objid,downtimesince,device,sensor,lastvalue,status,message,priority&filter_status=5&filter_status=4&filter_status=10&filter_status=13&filter_status=14&sortby=priority&username=GOES_HERE&passhash=GOES_HERE"
200# Where do you want to store the XML file?
201$destination = "C:\PRTG-DAILY-EMAIL\table.xml"
202# What colors do you like for each alert?
203# You have a lot to choose from https://msdn.microsoft.com/en-us/library/aa358802.aspx
204$AckColor = "LightPink"
205$AckMsg = "Down (Acknowledged) "
206$DownColor = "Red"
207$DownMsg = "Down "
208$WarnColor = "Yellow"
209$WarnMsg = "Warning "
210$SimColor ="DarkSalmon"
211$SimMsg = "Down  (simulated error)"
212$outfile ="C:\PRTG-DAILY-EMAIL\HTML.htm"
213 
214# Let's run the powershell script
215 
216Invoke-WebRequest $url -Outfile $destination
217$xml = [xml](Get-Content .\table.xml)
218# If nothing is alerting in PRTG we don't need to stay around. Let's say something about it and quit out.
219if ($xml.sensors.totalcount -eq 0) {
220ConvertTo-Html -Body $c | Out-File $outfile
221$emailbody = Get-Content $outfile | Out-String
222send-MailMessage -BodyAsHtml -SmtpServer $smtp -To $to -Cc $cc -From $from -Subject $subject -body $emailbody
223exit
224}
225$HTML = $xml.sensors.item | Sort-Object -Property device | select device,downtimesince,sensor,status,message_raw |
226ConvertTo-HTML -head $a -body $b
227$HTML = $HTML | Set-cellcolor status $WarnColor -Filter "status -eq '$WarnMsg'"
228$HTML = $HTML | Set-cellcolor status $DownColor -Filter "status -eq'$DownMsg'"
229$HTML = $HTML | Set-cellcolor status $AckColor -Filter "status -eq'$AckMsg'"
230$HTML = $HTML | Set-cellcolor status $SimColor -Filter "status -eq'$SimMsg'"
231$HTML | Out-File $outfile
232$emailbody = Get-Content $outfile | Out-String
233send-MailMessage -BodyAsHtml -SmtpServer $smtp -To $to -Cc $cc -From $from -Subject $subject -body $emailbody
234exit

So in the end you should get an email that looks something below if something is wrong. That's all I got I hope this information is helpful feel free to edit this and use it!

https://www.paessler.com/