Chapter 9: Automated Reporting and Email Integration
Automation Overview
Beyond producing interactive browser-based dashboards saved as local .html files, PSWriteHTML includes specialized functionality for automated email reporting. Sending rich HTML emails via PowerShell often presents challenges because major mail clients (especially desktop Microsoft Outlook) use restrictive rendering engines that strips external stylesheets, CSS grids, and JavaScript.
PSWriteHTML solves this by providing dedicated email layout cmdlets (Email, EmailBody, EmailLayoutRow, EmailLayoutColumn)
that automatically inline CSS styles into raw table-based HTML compatible with legacy email clients.
HTML Email Architecture vs. Web Dashboards
When building content for email delivery, standard web layouts (like New-HTML, JavaScript-based DataTables, and ApexCharts) should not be used
directly because email clients block external scripts and dynamic DOM manipulation for security reasons.
Key Email Constraints & Differences
Feature |
Web Dashboard ( |
Email Report ( |
|---|---|---|
Primary Container |
|
|
Layout Model |
Responsive CSS Flex/Grid Panels |
Inlined Table-based Rows & Columns |
JavaScript Support |
Full (DataTables, ApexCharts) |
None (Blocked by mail clients) |
CSS Handling |
Linked / Embedded Head Styles |
Direct Inline CSS ( |
Image Delivery |
Web URLs or local relative paths |
Inline images or CID (Content-ID) MIME attachments |
Building HTML Emails (Email / EmailBody)
To construct and send an email, use the Email
cmdlet with an -Email script block. Use EmailBody
together with EmailLayout, EmailLayoutRow, and EmailLayoutColumn to build the table-based body. These commands apply
email-safe layout and styling directly to the generated HTML.
Basic Email Template Structure
# Generate and send an email with an inlined HTML body
Email -To 'infrastructure@example.com' -From 'reports@example.com' `
-Subject 'Morning backup status' -Server 'smtp.example.com' -Port 587 -SSL -Email {
EmailBody {
EmailLayout {
EmailLayoutRow {
EmailLayoutRow {
EmailLayoutColumn {
New-HTMLText -Text "Below is the automated morning backup status summary."
}
}
EmailLayoutRow {
EmailLayoutColumn {
New-HTMLTable -DataTable $BackupResults -DisablePaging
}
}
EmailLayoutRow {
EmailLayoutColumn {
}
Note
EmailLayoutRow and
EmailLayoutColumn replace dashboard sections and panels
for this purpose. They ensure email clients render the multi-column layout using native HTML <table> rows and cells.
Embedding Images in Email Reports (New-HTMLImage)
External image links (e.g., <img src="https://...">) may be blocked by default in Microsoft Outlook and Apple Mail until the recipient
clicks “Download Images”. To ensure logos and status icons display immediately, embed images directly using
New-HTMLImage .
For a self-contained HTML body, use New-HTMLImage -Inline. This embeds the image data in the generated markup and avoids relying on
external image URLs. CID inline images are delivery-library-specific. The mail client library must add the image as an inline MIME
attachment, assign it a unique Content-ID such as CompanyLogo, and include that same identifier in the HTML as
src="cid:CompanyLogo". A cid: reference by itself is only a pointer; without the matching MIME attachment and Content-ID, the
recipient’s mail client cannot load the image.
Email -Email {
EmailBody {
EmailLayout {
EmailLayoutRow {
EmailLayoutColumn {
New-HTMLImage -Source 'C:\Reports\CompanyLogo.png' -Inline -AlternativeText 'Company logo' -Width 150
New-HTMLText -Text '<h2>Daily Audit Summary</h2>'
}
}
}
}
}
Sending the Email Report via SMTP or Microsoft Graph
The Email cmdlet can deliver the generated body directly. If another delivery library is required, use its HTML-body option and pass
the output from Email -OutputHTML to that library.
Method 1: Native Send-MailMessage (Legacy SMTP)
# The built-in PowerShell cmdlet Send-MailMessage is obsolete.
# Keep this only for existing legacy SMTP scripts.
Send-MailMessage -To 'admin@company.com' -From 'reports@company.com' `
-Subject "Daily System Health Check - $(Get-Date -Format 'yyyy-MM-dd')" `
-Body $EmailBody -BodyAsHtml -SmtpServer 'smtp.company.com' -Port 25
Method 2: Microsoft Graph API (Modern Cloud Delivery)
For Office 365 environments where basic SMTP authentication is disabled, send the generated HTML email via Microsoft Graph PowerShell SDK:
# Requires Microsoft.Graph.Mail module
Import-Module Microsoft.Graph.Mail
$Message = @{
Subject = "Automated Storage Alert"
Body = @{
ContentType = "Html"
Content = $EmailBody
}
ToRecipients = @(
@{ EmailAddress = @{ Address = "admin@company.com" } }
)
}
Send-MgUserMail -UserId "reports@company.com" -Message $Message
Automating Generation via Windows Scheduled Tasks
To run reports automatically on a daily or weekly schedule, wrap your PowerShell data gathering and PSWriteHTML script into an automated Scheduled Task.
Creating the Scheduled Task via PowerShell
The following administrative script registers a daily task that executes an automated PSWriteHTML report at 06:00 AM every morning:
# Define Script Path
$ScriptPath = "C:\Automation\Scripts\Generate-DailyReport.ps1"
# Create Action: Execute PowerShell 7 / Windows PowerShell silently
$Action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-ExecutionPolicy Bypass -NoProfile -File `"$ScriptPath`""
# Create Trigger: Daily at 06:00 AM
$Trigger = New-ScheduledTaskTrigger -Daily -At "06:00 AM"
# Register Task under SYSTEM or Dedicated Service Account
Register-ScheduledTask -TaskName "PSWriteHTML_DailyReport" `
-Action $Action `
-Trigger $Trigger `
-User "NT AUTHORITY\SYSTEM" `
-RunLevel Highest
Complete End-to-End Operational Example
The following complete script collects disk space usage, builds a highlighted inline HTML table, generates an email body, and dispatches an automated alert email if any drive drops below critical thresholds:
# 1. Collect Volume Data
$DiskDrives = Get-CimInstance Win32_LogicalDisk |
Where-Object DriveType -eq 3 |
Select-Object DeviceID,
@{N='SizeGB'; E={[math]::Round($_.Size/1GB, 2)}},
@{N='FreeGB'; E={[math]::Round($_.FreeSpace/1GB, 2)}},
@{N='FreePercent'; E={[math]::Round(($_.FreeSpace/$_.Size)*100, 1)}}
# 2. Select drives that require an alert
$LowDiskDrives = $DiskDrives | Where-Object FreePercent -lt 15
if ($LowDiskDrives) {
# 3. Build and send the inlined HTML email body
Email -To 'sysadmin@company.com' -From 'alerts@company.com' `
-Subject "STORAGE WARNING: $env:COMPUTERNAME Low Disk Space Alert" -Server 'smtp.company.com' -Email {
EmailBody {
# Banner Header
EmailLayout {
EmailLayoutRow {
EmailLayoutColumn {
New-HTMLText -Text "<h2 style='margin:0;'>Critical Storage Status Alert</h2>"
New-HTMLText -Text "System evaluation completed on <b>$env:COMPUTERNAME</b>."
}
}
}
# Data Grid with Conditional Formatting
EmailLayoutRow {
EmailLayoutColumn {
New-HTMLTable -DataTable $LowDiskDrives -DisablePaging {
# Column Formatting
New-TableColumnOption -ColumnIndex 0 -Width '20%'
New-TableColumnOption -ColumnIndex 3 -Width '20%'
# Highlight low disk space in red
New-TableCondition -Name 'FreePercent' -ComparisonType number -Operator lt -Value 15 -BackgroundColor '#FFCDD2' -Color '#B71C1C'
}
}
}
# Footer Section
EmailLayoutRow {
EmailLayoutColumn {
New-HTMLText -Text "<p style='font-size: 11px; color: #777;'>Automated message generated by PSWriteHTML Reporting Engine.</p>"
}
}
}
}
# 3. Deliver Email via SMTP
$SmtpParams = @{
To = 'sysadmin@company.com'
From = 'alerts@company.com'
Subject = "STORAGE WARNING: $env:COMPUTERNAME Low Disk Space Alert"
Body = $EmailContent
BodyAsHtml = $true
SmtpServer = 'smtp.company.com'
}
Send-MailMessage @SmtpParams
Email Automation Best Practices
Use ``Email`` for Emails, ``New-HTML`` for Web Pages: Never use standard
New-HTMLdirectly inside an email body. Desktop mail clients like Outlook will strip non-inlined CSS and script blocks.Disable DataTables Interactivity in Emails: Always set
-Paging $falseand-Filtering $falseonNew-HTMLTableinside email blocks, as email clients cannot run the JavaScript engine required for search and paging.Specify Explicit Widths: Use explicit table and column percentage widths (e.g.,
width="100%") to prevent email templates from rendering distorted on mobile email clients.
Next Chapter: Chapter 10: Advanced Features, Tips, and Troubleshooting