powershell [发送自定义HTML通知]最近,我们更改了PRTG处理通知电子邮件的方式并简化了方法,因此只有

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了powershell [发送自定义HTML通知]最近,我们更改了PRTG处理通知电子邮件的方式并简化了方法,因此只有相关的知识,希望对你有一定的参考价值。

#Requires -Version 4
<#
 ___ ___ _____ ___
| _ \ _ \_   _/ __|
|  _/   / | || (_ |
|_| |_|_\ |_| \___|
HTMLMailNotifier
With this, you can send personalized HTML mails using templates and PRTGs EXE notification
#>
param(
    ## From    
    [string] $From = "",
    ## Sensor ID
    [int] $SensorID = 0,
    ## The recipient of the mail message
    [string] $Recipients = "",
    ## Set this if you want to use a PRTG group as recipient
    [string] $PrtgGroup = "",
    ## The subjecty of the message
    [string] $Subject = "",
    ## The template folder
    [string] $TemplateFolder = "",
    ## The template we'll use
    [string] $Template = "",
    ## Placeholder set
    $Placeholders = @(),
    ## Use HTML or text based template (this will use the .htm instead of the .txt file for the template)
    $HTML = $true,
    ## The priority of the mail 
    [ValidateSet("Low","Normal","High")][string]$priority = "High",
    ## Only use primary contact - if false, all mail contacts will receive the notification
    [switch] $primaryOnly = $true,
    ## For the initial password setup, call it with -SetupPasswords
    [switch] $SetupPasswords = $false
)
#region configuration
[string] $ConfigurationFilePath = ((Get-ItemProperty -Path "hklm:SOFTWARE\Wow6432Node\Paessler\PRTG Network Monitor\Server\Core" -Name "Datapath").DataPath) + "PRTG Configuration.dat"
   [xml] $configuration = New-Object -TypeName XML;
         $configuration.Load($ConfigurationFilePath)
## server configuration
[hashtable]$servers = @{
  smtpFrom       = $From
  smtpHost       = ""
  smtpPort       = 0
  smtpUser       = ""
  smtpSsl        = $false
  smtpBackupFrom = $From
  smtpBackupHost = ""
  smtpBackupPort = 0
  smtpBackupUser = ""
  smtpBackupSsl  = ""
  prtgHost       = ""
  prtgPort       = 80
  prtgProtocol   = "http"
  prtgUsername   = ""
  prtgPasshash   = ""
}

## mail configuration
[System.Collections.ArrayList]$global:recipientList = @();
[string] $priority              = "high"
## template configuration
[string] $templateBaseDir       = "C:\Program Files (x86)\PRTG Network Monitor\webroot\mailtemplates\custom"
[string] $templateDefaultLogo   = "C:\Program Files (x86)\PRTG Network Monitor\webroot\images\prtglogo.png"
[string] $Global:graphGUID      = [guid]::NewGuid()
[string] $iconFolder            = "C:\Program Files (x86)\PRTG Network Monitor\webroot\icons"
[string] $tempFolder            = "C:\temp";
[string] $global:stateIcon      = "";
## miscallenious
[hashtable]$directories = @{
    "templateBaseDir" = "C:\Program Files (x86)\PRTG Network Monitor\webroot\mailtemplates\custom";
    "tempFolder"      = "C:\temp";
    "iconFolder"      = "C:\Program Files (x86)\PRTG Network Monitor\webroot\icons";
    "templatePath"    = ""; }
###########################################################################
# /!\ DON'T CHANGE ANYTHING BELOW - Except you know what you're doing /!\ #
###########################################################################
[hashtable] $stateColors = @{
       "1" = "#808282"; #unknown
       "3" = "#b4cc38"; #up
       "4" = "#ffcb05"; #warning
       "5" = "#d71920"; #down
       "8" = "#447fc1"; #paused-dependency
       "9" = "#447fc1"; #paused-schedule
       "10" = "#f99d1c"; #unusual
       "11" = "#447fc1"; #paused-license
       "12" = "#447fc1"; #paused-until
       "13" = "#e77579"; #acknowledged
       "14" = "#d71920"; #down-partial
       }
[hashtable]$stateIcons = @{
       "1" = "led_grey.png";    #unknown
       "3" = "led_green.png";   #up
       "4" = "led_yellow.png";  #warning
       "5" = "led_red.png";     #down
       "8" = "led_blue.png";    #paused-dependency
       "9" = "led_blue.png";    #paused-schedule
       "10" = "led_orange.png"; #unusual
       "11" = "led_blue.png";   #paused-license
       "12" = "led_blue.png";   #paused-until
       "13" = "led_redok.png";   #acknowledged
       "14" = "led_redgreen.png";#down-partial
}
## debugging
[switch] $verbose = $true;
#endregion
 
#region function library
## show messages, nicely formatted.
function Console-ShowMessage([string]$type,$message){
    if($verbose){
        Write-Host ("[{0}] [" -f (Get-Date)) -NoNewline;
        switch ($type){
            "done" { Write-Host "done" -ForegroundColor Green -NoNewline;}
            "info" { Write-Host "info"    -ForegroundColor DarkCyan -NoNewline; }
            "warn" { Write-Host "warn" -ForegroundColor DarkYellow -NoNewline; }
            "fail" { Write-Host "fail"   -ForegroundColor Red -NoNewline; }
            default{ Write-Host $type -NoNewline; }
        }
        Write-Host ("]`t{0}{1}" -f $message,$Global:blank)
    }
}
## check the password files for completeness
function Check-PasswordFiles(){
    $checklist = @("Primary","Secondary")
    foreach($server in $checklist){
        $fileCount = (Get-ChildItem "C:\Program Files (x86)\PRTG Network Monitor\Notifications\EXE\*" -Include "*$($server).key","*$($server).pass").Count
        if(!($fileCount -eq 2)){
            Console-ShowMessage "fail" "The credential set for the $($server) server is missing or incomplete."
            Passwords Set $server
        }
     }
     if($SetupPasswords){ PRTG-ShowMessage "info" "Credentials created successfully."; exit 0; }
    if((Get-ChildItem "C:\Program Files (x86)\PRTG Network Monitor\Notifications\EXE\*" -Include "*.key","*.pass").Count -eq 4){
        Console-ShowMessage "done" "All credentials found."
    }
}
## check the mail server availability
function Check-MailServers([hashtable]$global:servers){
    begin { Console-ShowMessage "info" "Checking mail server availability..." }
    process {
        ## lets create a new TCP client first
        $tcpClient = New-Object System.Net.Sockets.TCPClient
        try{
          $tcpClient.Connect($global:servers.smtpHost,$global:servers.smtpPort)
          Console-ShowMessage "info" "Using primary mail server"
        }
        catch{
          try {
            $tcpClient.Connect($global:servers.smtpBackupHost,$global:servers.smtpBackupPort)
            Console-ShowMessage "warn" "Primary mail server not responding, using fallback server"
            $global:servers.smtpHost = $global:servers.smtpBackupHost
            $global:servers.smtpPort = $global:servers.smtpBackupPort
            $global:servers.smtpSsl  = $global:servers.smtpBackupSsl
            $global:servers.smtpUser = $global:servers.smtpBackupUser
          }
          catch {
            Console-ShowMessage "fail" "None of the configured mailservers is responding, please check them for availability."
            #exit 1;
          }
        }
        finally { $tcpClient.Close(); }
    }
}
function ValidateEmail{
    param([string]$address)
    ($address -as [System.Net.Mail.MailAddress]).Address -eq $address -and $address -ne $null
}
## store the passwords
function Passwords([ValidateSet("Get","Set")][string]$action, [ValidateSet("Primary","Secondary")][string]$Server = ""){
    switch($Server)
    {
            "primary"   {
                $passFile = "C:\Program Files (x86)\PRTG Network Monitor\Notifications\EXE\HTMLNotifyPrimary.pass";
                $keyFile  = "C:\Program Files (x86)\PRTG Network Monitor\Notifications\EXE\HTMLNotifyPrimary.key";
             }
            "secondary" {
                $passFile = "C:\Program Files (x86)\PRTG Network Monitor\Notifications\EXE\HTMLNotifySecondary.pass"
                $keyFile  = "C:\Program Files (x86)\PRTG Network Monitor\Notifications\EXE\HTMLNotifySecondary.key";   
            }
    }
    if($action -eq "set"){
        $Key = New-Object Byte[] 32
        [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
        $Key | out-file $keyFile
        Read-Host "Enter Password for the $($Server) server" -AsSecureString |  ConvertFrom-SecureString -key $Key | Out-File $passFile
    }
    if($action -eq "get"){
       $Key = Get-Content $KeyFile
       $Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $global:servers.smtpUser, (Get-Content $passFile | ConvertTo-SecureString -Key $key)
       return $Credentials;
    }
}
## set up the template paths
function Set-TemplatePaths(){
    begin { Console-ShowMessage "info" "Setting up template paths..." }
    process {
        ## set up the paths...
        if($templateFolder.Length -ne 0)
        { $directories.templatePath = [string]::Format("{0}\{1}\{2}.htm",$templateBaseDir,$templateFolder,$Template) }
        else
        { $directories.templatePath =  [string]::Format("{0}\{1}.htm",$templateBaseDir,$Template) }
        ## Check the paths for existance
        $directories.Keys | % {
            if(!(Test-Path $directories.Item($_)))
                { Write-Host "Template or directory not found. Please make sure all folders and templates exist!" -ForegroundColor Red; exit 2; }
            }
        ## if there's no logo, use the default
        if(!(Test-Path -Path ([string]::Format("{0}\{1}\logo.png",$templateBaseDir,$templateFolder))))
        {
          $global:templateLogo = $templateDefaultLogo
          Console-ShowMessage "info" "No customized logo found, using the specified default logo..."
        }
        else
        {
          Console-ShowMessage "info" "Customized logo found."
          $global:templateLogo = [string]::Format("{0}\{1}\logo.png",$templateBaseDir,$templateFolder)
        }
    }
}
## this function will return the group ID of the given group
function Get-PrtgGroup( [string]$prtgGroup ){
     
    if($prtgGroup.Length -ne 0){
        ## retrieve the group id of the corresponding PRTG user group
        $group = $configuration.SelectSingleNode([string]::Format('//usergroup[@id][data/name[normalize-space(text())="{0}"]]',$prtgGroup))
        ## return the id, otherwise error if you found nothing
        if($group -ne $null)
        { return $group.id.Trim(); }
        else
        { Console-ShowMessage -type "fail" "The specified user group was not found. Please make sure that the name is correct." }
    }
}
## this will retrieve the single users from PRTG and create the recipientList
function Get-PrtgUsers([string]$prtgGroup){
    begin { Console-ShowMessage -type "info" "Retrieving recipients..." }
    process {
         
        if($prtgGroup.Length -ne 0){
         
        Console-ShowMessage -type "info" "Retrieving users of PRTG group $($prtgGroup)"
         
        ## lets retrieve the ID of the corresponding group first.
        $groupId  = (Get-PrtgGroup -prtgGroup $prtgGroup)
        ## now lets get all active users within that group
        $userList = $configuration.SelectNodes([string]::Format('//user[@id][data/primarygroup = {0}][data/active = 1]',$groupId))
        $availableUsers = Foreach($user in $userList){
                ## we only want the primary contacts if PrimaryOnly is true.
                if($PrimaryOnly)
                { $contacts = $user.SelectNodes('//user[@id='+$user.id+']/contacts/contact[data/status = 1][data/contacttype = 0][@id = -100]') }
                else
                { $contacts = $user.SelectNodes('//user[@id='+$user.id+']/contacts/contact[data/status = 1][data/contacttype = 0]') }
                $availableContacts = foreach($contact in $contacts)
                { $recipientList.Add($contact.data.recipient.Trim()) }
        }
         
        ## create the final recipient list and remove duplicates
        $recipients = $recipientList + $recipients.Trim().Split(",") | Select -Unique      
        }
        else
        {
          $recipients = $recipients.Trim().Split(",") | Select -Unique
        }
         
        $correctedRecipients = @();
           
        # remove all recipients that are not valid
        foreach($recipient in $recipients){
            if(ValidateEmail($recipient))
            { $correctedRecipients += $recipient }
        }
    }
     
    end {
        # stop it if we don't have any recipients
        if($correctedRecipients.Length -eq 0) { Console-ShowMessage -type "fail" "No recipients found. Please check the group name and the recipient list for errors. Exiting."; exit 0; }
        Console-ShowMessage -type "done" "Found $($userList.count) users in group $($prtgGroup), sending to $($correctedRecipients.count) contacts in total."
        return $correctedRecipients;
    }
}
## this function will retrieve the latest sensor informations
function Get-SensorLiveInfo([int]$SensorId){
    begin { Console-ShowMessage -type "info" "Retrieving information for sensor #$($SensorID)" }
    process {
       ## build the graph URL
        $params = @($global:servers.prtgProtocol,$global:servers.prtgHost,$global:servers.prtgPort,$SensorId,$global:servers.prtgUsername,$global:servers.prtgPasshash)
        $url = [string]::Format("{0}://{1}:{2}/api/getsensordetails.json?id={3}&username={4}&passhash={5}",$params);
        ## download the graph and store it with the current guid
        $wc = New-Object System.Net.WebClient
        $sensorInfo = ($wc.DownloadString($url)) | ConvertFrom-Json;
    }
    end { return $SensorInfo }
}
## retrieves the live graph from the given sensor id
function Get-SensorLiveGraph([int]$id){
    begin { Console-ShowMessage -type "info" "Retrieving current live graph for sensor #$($SensorID)" }
    process {
        ## build the graph URL
        $params = @($global:servers.prtgProtocol,$global:servers.prtgHost,$global:servers.prtgPort,600,280,$SensorId,$global:servers.prtgUsername,$global:servers.prtgPasshash)
        $url = [string]::Format("{0}://{1}:{2}/chart.png?type=graph&width={3}&height={4}&graphid=0&id={5}&username={6}&passhash={7}",$params);
        ## download the graph and store it with the current guid
        $wc = New-Object System.Net.WebClient
        $wc.DownloadFile($url, [string]::Format("{0}\{1}.png",$directories.tempFolder,$Global:GraphGUID))
    }
    end { Console-ShowMessage -type "done" "Graph downloaded and stored as $($tempFolder)\$($Global:GraphGUID).png" }
}
## sets up the template and replaces the placeholders accordingly.
function Get-Template(){
    begin { Console-ShowMessage "info" "Preparing notification mail" }
    process {
        ## retrieve current sensor information
        $SensorInfo = (Get-SensorLiveInfo($SensorID))
        ## set the status icon
        $global:stateIcon = $stateIcons[$SensorInfo.sensordata.statusid]
        ## retrieve the template of the specified content
        [string]$body = (Get-Content $directories.templatePath) -join "`n"
        ## check if the amount of placeholders does match
        try
        {$body = [string]::Format($body,$placeholders) }
        catch
        { Console-ShowMessage "warn" "The amount of placeholders doesn't match with the template. Please make sure that they're equal." }
        [hashtable]$placeholderTable = @{
            "miscLOGO"             = [string]::Format("<img src='{0}' />",(Split-Path -Path $global:templateLogo -Leaf))
            "sensorNAME"           = $SensorInfo.sensordata.name;
            "sensorTYPE"           = $SensorInfo.sensordata.sensortype;
            "sensorLIVEGRAPH"      = [string]::Format("<img src='{0}.png' />",$Global:GraphGUID);
            "sensorSTATECOLOR"     = $stateColors[$SensorInfo.sensordata.statusid];
            "sensorSTATEICON"      = [string]::Format("<img src='{0}' />",$global:stateIcon)
            "sensorINTERVAL"       = $SensorInfo.sensordata.interval;
            "sensorPARENTGROUP"    = $SensorInfo.sensordata.parentgroupname;
            "sensorPARENTDEVICE"   = $SensorInfo.sensordata.parentdevicename;
            "sensorPARENTDEVICEID" = $SensorInfo.sensordata.parentdeviceid;
            "sensorLASTVALUE"      = $SensorInfo.sensordata.lastvalue;
            "sensorLASTMESSAGE"    = $SensorInfo.sensordata.lastmessage;
            "sensorSTATUSTEXT"     = $SensorInfo.sensordata.statustext;
            "sensorSTATUSID"       = $SensorInfo.sensordata.statusid;
            "sensorLASTUP"         = $SensorInfo.sensordata.lastup;
            "sensorLASTDOWN"       = $SensorInfo.sensordata.lastdown;
            "sensorLASTCHECK"      = $SensorInfo.sensordata.lastcheck;
            "sensorUPTIME"         = $SensorInfo.sensordata.uptime;
            "sensorUPTIMETIME"     = $SensorInfo.sensordata.uptimetime;
            "sensorDOWNTIME"       = $SensorInfo.sensordata.downtime;
            "sensorDOWNTIMETIME"   = $SensorInfo.sensordata.downtimetime;
            "sensorUPDOWNTOTAL"    = $SensorInfo.sensordata.uptimetotal;
            "sensorUPDOWNSINCE"    = $SensorInfo.sensordata.updownsince;
            "sensorURL"            = [string]::Format("{0}://{1}:{2}/sensor.htm?id={3}",$global:servers.prtgProtocol,$global:servers.prtgHost,$global:servers.prtgPort,$SensorID);
            "deviceURL"            = [string]::Format("{0}://{1}:{2}/device.htm?id={3}",$global:servers.prtgProtocol,$global:servers.prtgHost,$global:servers.prtgPort,$SensorInfo.sensordata.parentdeviceid);
            }
        ## replace all existing placeholders within the template
        foreach ($placeholder in $placeholderTable.Keys)
        {
            $body = ($body -replace $placeholder, $placeholderTable.$placeholder)
            $subject = ($subject -replace $placeholder, $placeholderTable.$placeholder)
        }
        [hashtable]$mail = @{
            Body = $body;
            Subject = $subject;
        };
    }
    end { return $mail }
}
## this function will format the mail and send it to the given recipient(s)
function Send-NotificationMail([hashtable]$mail){
        ## There will always be a logo and a livegraph available for every template.
        ## Use logo,livegraph,probeicon,breadcrumb as img src to embed them, like this:
        ## See the following placeholders to insert them in your mail
        [string[]]$images = @(
            $global:templateLogo,
            [string]::Format("{0}\{1}.png",$directories.tempFolder,$Global:GraphGUID),
            [string]::Format("{0}\{1}",$directories.iconFolder,$global:stateIcon)
        )
    $mailparameters = @{
        SmtpServer       = $global:servers.smtpHost;
        Port             = $global:servers.smtpPort;
        Credential       = (Passwords -Action Get -Server Primary);
        From             = $global:servers.smtpFrom;
        To               = Get-PrtgUsers($prtgGroup);
        Body             = $mail.Body;
        Subject          = $mail.Subject;
        Attachments      = $images;
        BodyAsHtml       = $HTML;
        UseSsl           = $global:servers.smtpSsl;
        Priority         = $priority;
    }
    try{
        Send-MailMessage @mailparameters
        Console-ShowMessage "info" "Recipient(s) should be notified now."
    }
    catch { PRTG-ShowMessage "fail" "The notification could not be sent." }
}
#endregion
function Main(){
        begin{
          Check-PasswordFiles;
          Check-MailServers;
          Set-TemplatePaths;
        }
        process{
          Get-SensorLiveGraph;
          Send-NotificationMail -mail (Get-Template)
        }
        end{
          Console-ShowMessage "info" "Removing live graph image. Exiting."
          Remove-Item ([string]::Format("{0}\{1}.png",$tempFolder,$Global:graphGUID))
        }
}
Main;

以上是关于powershell [发送自定义HTML通知]最近,我们更改了PRTG处理通知电子邮件的方式并简化了方法,因此只有的主要内容,如果未能解决你的问题,请参考以下文章

PowerShell 实现企业微信机器人推送消息

Powershell 查看日志并发送电子邮件通知

OneSignal - 使用来自 url 的自定义图像从 android 应用发送通知

Powershell + Nagios 监控 VEEAM 备份状态

如何使用 OneSignal 发送自定义声音推送通知?

在本地通知上发送带有自定义声音的触觉