, ,

HTML E-Mail Report Generator

Overview

I created this series of functions to allow you to conveniently take one or more PowerShell object and have it turn into an email report. For example, if you had a list of computers you have come out of a PowerShell script you wrote, these functions could help you turn them into an email with the same data without much effort.

Create an Email with A Simple Array of Data: EASY

Import-Module \\scriptserver\scripts\Get-DGMEmailReport\Get-DGMEmailReport.psm1 -Force

Import-Module \\pathtoscriptfile\Get-DGMEmailReport.psm1 -Force


$myarray = (Get-ADComputer -properties Description -filter {description -like "*sql*"} | Select Name,Description)

#Single Array Email Report
Get-DGMEmailReport `
    -Array $myarray `
    -ArrayTitle "SQL Servers" `
    -ArrayTitleColor "Blue" `
    -ArrayMessage "These are all the SQL Servers" `
    -ReportTitle "SQL Report 2017" `
    -from "SQLReports@emailaddress.com" `
    -To "c-dmaiolo@emailaddress.com" `
    -subject "SQL Test Report"  

Create an Email With Multiple Arrays of Data: MODERATE DIFFICULTY



Import-Module \\pathtoscriptfile\Get-DGMEmailReport.psm1 -Force 

#Create Some Arrays Of Data To Display in Report. You can create as many as you want.
$OutputArrays = @()
   
#Array1
$output = [PSCustomObject] @{
'Message' = "These are deployments older than 90 days, with lower than an 80% success rate where 100 or more computers were targeted.";
'Title' = "SCCM Problem Deployments";
'Color' = "Red";
'Array' = Get-DGMSCCMProblemDeploymentsArray -Days 90 -PercentSuccessThreshold .8 -NumberOfTargetedThreshold 100;
}

$OutputArrays+=$output

#Array2
$output = [PSCustomObject] @{
'Message' = "These are all deployments that were deployed over a year ago.";
'Title' = "SCCM Deployments Greater Than 1 Year Old";
'Color' = "Green";
'Array' = Get-DGMSCCMProblemDeploymentsArray -Days 365 -PercentSuccessThreshold 1 -NumberOfTargetedThreshold 0;
}
    
$OutputArrays+=$output
    
#Array3
$output = [PSCustomObject] @{
'Message' = "These are all our SQL Servers.";
'Title' = "SQL Servers";
'Array' = Get-ADComputer -properties Description -filter {description -like "*sql*"} | Select Name,Description
}

$OutputArrays+=$output 

#Multiple Arrays Email Report
Get-DGMEmailReport `
    -Arrays $OutputArrays `
    -ReportTitle "SQL Report 2017" `
    -from "SQLReports@emailaddress.com" `
    -To "c-dmaiolo@emailaddress.com" `
    -subject "SQL Test Report" 

Sample Single Array Output

cid:image002.jpg@01D38FBC.5C3028C0

Sample Multiple Array Output Email

cid:image003.jpg@01D38FBC.5C3028C0

PowerShell Functions


<#
.SYNOPSIS
  Generates an Email Report
.NOTES
  Version:        1.0
  Author:         David Maiolo
  Creation Date:  2018-01-02
  Purpose/Change: Initial script development

#>

#---------------------------------------------------------[Initialisations]--------------------------------------------------------

Import-Module \\scriptserver\scripts\DMGSCCM\New-DMGCMTraceLog\New-DMGCMTraceLog.psm1 -Force

function New-DMGCombinedHTMLTable{
 param(
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        $DMGCombinedHTMLTable
    )
    $CombinedHTML = ""
    
    foreach ($object in $DMGCombinedHTMLTable){

            $CombinedHTML+= "
" if ($object.Title){ if ($object.Color){ $CombinedHTML+= "" #$CombinedHTML+= "

"+($object.Title)+"

" $CombinedHTML+= "

"+($object.Title)+"

" }else{ $CombinedHTML+= "

"+($object.Title)+"

" } } if($object.Message){ $CombinedHTML+= "

➥ "+($object.Message)+"

" } if ($object.Array){ $CombinedHTML+= $object.Array | ConvertTo-Html } $CombinedHTML+= "
" } return $CombinedHTML } function New-DMGHTMLTable{ param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)] $Array, [Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true)] $Title, [Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true)] $Message, [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true)] [ValidateSet("Black","White","Red","Lime","Blue","Yellow","Cyan","Magenta","Silver","Gray","Maroon","Olive","Green","Purple","Teal","Navy")] $Color ) $HTML = "" $HTML+= "
" if([bool]($MyInvocation.BoundParameters.Keys -match 'Title')){ if([bool]($MyInvocation.BoundParameters.Keys -match 'Color')){ $HTML+= "" } $HTML+= "

"+($Title)+"

" } if([bool]($MyInvocation.BoundParameters.Keys -match 'Message')){ $HTML+= "

➥ "+($Message)+"

" } if([bool]($MyInvocation.BoundParameters.Keys -match 'Array')){ $HTML+= $Array | ConvertTo-Html } $HTML+= "
" return $HTML } function New-DMGEmailReport{ param( [Parameter(Position=0,Mandatory=$false,ValueFromPipeline=$true,ParameterSetName='Multiple Arrays')] $Arrays, [Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true,ParameterSetName='Single Array')] $Array, [Parameter(Position=2,Mandatory=$false,ValueFromPipeline=$true,ParameterSetName='Single Array')] $ArrayMessage, [Parameter(Position=3,Mandatory=$false,ValueFromPipeline=$true,ParameterSetName='Single Array')] $ArrayTitle, [Parameter(Position=9,Mandatory=$false,ValueFromPipeline=$true,ParameterSetName='Single Array')] [ValidateSet("Red","Yellow","Green","Black")] $ArrayTableColor = "Black", [Parameter(Position=4,Mandatory=$true,ValueFromPipeline=$true)] $From, [Parameter(Position=5,Mandatory=$true,ValueFromPipeline=$true)] $To, [Parameter(Position=6,Mandatory=$true,ValueFromPipeline=$true)] $Subject, [Parameter(Position=7,Mandatory=$true,ValueFromPipeline=$true)] $ReportTitle, [Parameter(Position=8,Mandatory=$false,ValueFromPipeline=$true)] $SmtpServer = "mail.emailaddress.com", [Parameter(Position=9,Mandatory=$false,ValueFromPipeline=$true)] [Switch]$AttatchResults, [Parameter(Position=10,Mandatory=$false,ValueFromPipeline=$true)] [Switch]$AttatchSource ) #Set Logging Varibales $invocation = (Get-Variable MyInvocation -Scope 1).Value $ScriptDirectory = Split-Path $invocation.MyCommand.Path $ScriptName = ($MyInvocation.MyCommand.Name)+".psm1" $LogName = ($MyInvocation.MyCommand.Name)+".log" $LogFile = Join-Path $ScriptDirectory $LogName $ScriptFile = Join-Path $ScriptDirectory $ScriptName $ReportDate = Get-Date $WrapperScriptPath = $MyInvocation.PSCommandPath #Map a Drive to UNC Path New-PSDrive -Name UNCPath -PSProvider FileSystem -Root $ScriptDirectory #Log Start of Function New-DMGCMTraceLog -message ("Starting Logging for $ScriptName") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile #Create Attachments Directory If It Doesn't Exist if (!(Test-Path "UNCPath:\Attachments\")){ New-DMGCMTraceLog -message ("UNCPath:\Attachments\ Not Found. Created.") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile New-Item "UNCPath:\Attachments\" -ItemType Directory } if([bool]($MyInvocation.BoundParameters.Keys -contains 'Arrays')){ $HTMLTable = New-DMGCombinedHTMLTable -DMGCombinedHTMLTable $Arrays #Log New-DMGCMTraceLog -message ("An Array of Arrays Was Passed") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile if([bool]($MyInvocation.BoundParameters.Keys -contains 'AttatchResults')){ $attachment = @() foreach ($object in $Arrays){ $AttachmentName = (Remove-DMGInvalidFileNameChars($object.Title))+".csv" $AttachmentFile = Join-Path UNCPath:\Attachments\ $AttachmentName $object.Array | export-csv -path $AttachmentFile -notypeinformation $attachment += $AttachmentFile } New-DMGCMTraceLog -message ("Attatching multiple files: $attachment") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile } }elseif([bool]($MyInvocation.BoundParameters.Keys -contains 'Array')){ $HTMLTable = New-DMGHTMLTable -Array $Array -Message $ArrayMessage -Title $ArrayTitle -Color $ArrayTableColor #Log New-DMGCMTraceLog -message ("An Single Array Was Passed") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile if([bool]($MyInvocation.BoundParameters.Keys -contains 'AttatchResults')){ $attachment = @() $AttachmentName = (Remove-DMGInvalidFileNameChars($ArrayTitle))+".csv" $AttachmentFile = Join-Path UNCPath:\Attachments\ $AttachmentName $Array | export-csv -path $AttachmentFile -notypeinformation $attachment += $AttachmentFile } New-DMGCMTraceLog -message ("Attatching the single file: $Attachment") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile } #Construct HTML for Email $HTMLEmailMessage = @" CodeNarc Report: Sample Project

$Subject

$HTMLTable

Path to script: $ScriptFile

Path to log file: $LogFile

Path to script that called $ScriptName`: $WrapperScriptPath

"@ if([bool]($MyInvocation.BoundParameters.Keys -contains 'AttatchSource')){ if ($attachment -eq $null){$attachment = @()} $AttachmentName = (Remove-DMGInvalidFileNameChars($ReportTitle))+"_html_source.txt" $AttachmentFile = Join-Path UNCPath:\ $AttachmentName $HTMLEmailMessage | Out-File -FilePath $AttachmentFile $attachment += $AttachmentFile } #Send The Email if ($Attachment){ Send-MailMessage -From $from -To $To -Subject $subject -SmtpServer $smtpServer -BodyAsHtml -Body $HTMLEmailMessage -Attachments $Attachment #Log Sent Email New-DMGCMTraceLog -message ("Email Sent`: Subject`:$subject To`:$To From`:$From Attatchments`:$attachment") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile }else{ Send-MailMessage -From $from -To $To -Subject $subject -SmtpServer $smtpServer -BodyAsHtml -Body $HTMLEmailMessage #Log Sent Email New-DMGCMTraceLog -message ("Email Sent`: Subject`:$subject To`:$To From`:$From") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile } #Remove Attachments if (Test-Path "UNCPath:\Attachments\"){ Remove-Item "UNCPath:\Attachments\" -Recurse New-DMGCMTraceLog -message ("UNCPath:\Attachments\ Found. Removing files within.") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile } #Log End Of Function New-DMGCMTraceLog -message ("End Logging for $ScriptName") -component "Main()" -type 1 -ScriptName $ScriptName -LogFile $LogFile -ScriptFile $ScriptFile } function Get-DMGColorHexValue{ param( [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true)] [ValidateSet("Black","White","Red","Lime","Blue","Yellow","Cyan","Magenta","Silver","Gray","Maroon","Olive","Green","Purple","Teal","Navy")] $Color ) switch ($Color) { "Black" {"#000000"} "White" {"#FFFFFF"} "Red" {"#FF0000"} "Lime" {"#00FF00"} "Blue" {"#0000FF"} "Yellow" {"#FFFF00"} "Cyan" {"#00FFFF"} "Magenta" {"#FF00FF"} "Silver" {"#C0C0C0"} "Gray" {"#808080"} "Maroon" {"#800000"} "Olive" {"#808000"} "Green" {"#008000"} "Purple" {"#800080"} "Teal" {"#008080"} "Navy" {"#000080"} default {"#DDDDFF"} } } Function Remove-DMGInvalidFileNameChars { param( [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [String]$String ) $pattern = '[^a-zA-Z]' $CleanString = $String -replace $pattern return $CleanString }

PowerShell Code: The Logging Functions

Import this module to enable the logging functions.


function New-DGMCMTraceLog{
  param (
  [Parameter(Mandatory=$true)]
  $ScriptName,
  [Parameter(Mandatory=$true)]
  $LogFile,
  [Parameter(Mandatory=$true)]
  $ScriptFile,
  [Parameter(Mandatory=$true)]
  $message,
  [Parameter(Mandatory=$true)]
  $component,
  [Parameter(Mandatory=$true)]
  $type )

  $VerboseLogging = "true"
  [bool]$Verbose = [System.Convert]::ToBoolean($VerboseLogging)
  $MaxLogSizeInKB = 10240
  $ScriptStatus = 'Success'

  switch ($type)
  {
    1 { $type = "Info" }
    2 { $type = "Warning" }
    3 { $type = "Error" }
    4 { $type = "Verbose" }
  }

  if (($type -eq "Verbose") -and ($Verbose))
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $LogFile)
    Write-Host $message
  }
  elseif ($type -ne "Verbose")
  {
    $toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $LogFile)
    if ($type -eq 'Info') { Write-Host $message }
    if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow}
    if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red}
    

  }
  if (($type -eq 'Warning') -and ($ScriptStatus -ne 'Error')) { $ScriptStatus = $type }
  if ($type -eq 'Error') { $ScriptStatus = $type }

  if ((Get-Item $LogFile -ErrorAction SilentlyContinue).Length/1KB -gt $MaxLogSizeInKB)
  {
    $log = $LogFile
    Remove-Item ($log.Replace(".log", ".lo_"))
    Rename-Item $LogFile ($log.Replace(".log", ".lo_")) -Force
  }
} 
0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *