PowerShell

Working with HTML in PowerShell just got better

Last few weeks, I've been working on making creating HTML based Dashboards, Reports, and Emails better. PSWriteHTML already allows fancy looking reports or emails without much effort, but this release makes it even more helpful. I will be mixing three PowerShell modules in this blost post – PSWriteHTML (responsible for creating HTML/CSS/JS code), Emailimo (simplifies creating emails based on PSWriteHTML) and Dashimo (simple dashboard building). If you've never heard of those modules before I encourage you to start from earlier blogs about them to understand the concepts before you dive into this one.  Hopefully, those will give you some ideas that will match what you will learn today.

Also, this post means that following PowerShell module was updated in PSGallery. Before updating them on production, please test whether your code still works as required because I've done a lot of changes (even thou those shouldn't be visible) preparing for new features.

As always code on PowerShellGallery is optimized for speed, while the one stored on GitHub for development.

Inline Table Conditional Formatting and Styling Content in Emailimo

While I've made plenty of changes and added a couple of new features, I want to focus on Tables again. I know it was already a focus for me in earlier releases, but I was missing a crucial element. Conditional formatting and styling of content inline. While Conditional Formatting was already part of previous versions, it was based on JavaScript. That means conditional formatting happens while you open up your browser. Thanks to this there's almost no time spent on verification whether something matches condition or not while it's being generated in PowerShell. The drawback is it doesn't work when JavaScript is disabled, which is something widespread for emails. This release adds the ability to style content based on column and rows or use conditional formatting to apply style but make it permanent in HTML. Confusing? Let's take a look at a reasonably simple table of Domain Controllers in my test Active Directory Forest.

Creating this table in HTML is not trivial if you would like to do it manually. There are multiple things in play here. First of all, we have headers that span across two rows. We have headers that span across multiple columns. We also have green, yellow, and red colors in different parts of content to make data in them more accessible to spot on first look. While manually it would be hard to create with PSWriteHTML (and for that matter in Emailimo or Dashimo) it's quite easy if you understand the concepts. Since Table above is a screenshot from Email, I will be using Emailimo to describe features you see above.

$DomainControllers = Get-WinADDomainControllers -TestAvailability

EmailTable -DataTable $DomainControllers {
    EmailTableHeader -Names 'IPV4Address', 'IPV6Address' -Title 'Ip Addresses' -Alignment center -Color White -BackGroundColor Gray
    EmailTableHeader -Names 'SchemaMaster', 'PDCEmulator', 'RIDMaster', 'DomainNamingMasterMaster', 'InfrastructureMaster' -Title 'Roles' -Alignment center -Color White -BackGroundColor Gray
    EmailTableHeader -Names 'LdapPort', 'SslPort' -Title 'Ports' -Alignment center -Color White -BackGroundColor Gray
    EmailTableCondition -ComparisonType 'string' -Name 'SchemaMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
    EmailTableCondition -ComparisonType 'string' -Name 'PDCEmulator' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
    EmailTableCondition -ComparisonType 'string' -Name 'RIDMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
    EmailTableCondition -ComparisonType 'string' -Name 'IsReadOnly' -Operator eq -Value 'True' -BackgroundColor Yellow -Color Black -Inline
    EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
    EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator ne -Value 'True' -BackgroundColor Red -Color White -Inline
} -HideFooter

In code above, you see four functions: Get-WinADDomainControllers, which is getting me all my Domain Controllers within a forest (not part of today's blog). Then as you can see, I'm using three functions from Emailimo module – EmailTable, EmailTableHeader, and EmailTableCondition. First, you create a table with EmailTable; you open bracket to tell Emailimo that EmailTableHeader and EmailTableConditions function will apply to that table and nothing else and then you define their action. As you can see above, I've used three EmailTableHeader functions. I wanted to add a description and somehow connect all FSMO roles under one header called Roles. So I defined all Column Names and gave it a Title.

EmailTableHeader -Names 'SchemaMaster', 'PDCEmulator', 'RIDMaster', 'DomainNamingMasterMaster', 'InfrastructureMaster' -Title 'Roles' -Alignment center -Color White -BackGroundColor Gray

In the next case, I've two columns called LdapPort and SSLPort that I wanted to be visible under one name Ports. With Emailimo it's as simple as one command

EmailTableHeader -Names 'LdapPort', 'SslPort' -Title 'Ports' -Alignment center -Color White -BackGroundColor Gray

Of course, as you may have already noticed, I also gave it some BackgroundColor some Color for text and some alignment. But there are other styling options available. But you already knew that from my earlier blog, right? But here's the critical bit EmailTableCondition. In this case, I've defined five conditions. I wanted to color code all Domain Controllers where the FSMO roles are. I also wanted to color code computers which are pingable and mark those which aren't with red color. This was already covered in my blog post about Dashimo. What wasn't included is the switch Inline. That little switch is critical if you want the styling to work with JavaScript disabled (hence why I show this in Emailimo).

EmailTableCondition -ComparisonType 'string' -Name 'SchemaMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
EmailTableCondition -ComparisonType 'string' -Name 'PDCEmulator' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
EmailTableCondition -ComparisonType 'string' -Name 'RIDMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
EmailTableCondition -ComparisonType 'string' -Name 'IsReadOnly' -Operator eq -Value 'True' -BackgroundColor Yellow -Color Black -Inline
EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator ne -Value 'True' -BackgroundColor Red -Color White -Inline

How does it look in HTML?

<table id="DT-wmronOCJ" class="display compact">
    <thead>
        <tr>
            <th rowspan="2">Domain</th>
            <th rowspan="2">HostName</th>
            <th rowspan="2">Forest</th>
            <th style="color:#ffffff;background-color:#808080;text-align:center" colspan="2">Ip
                Addresses</th>
            <th rowspan="2">IsGlobalCatalog</th>
            <th rowspan="2">IsReadOnly</th>
            <th rowspan="2">Site</th>
            <th style="color:#ffffff;background-color:#808080;text-align:center" colspan="5">Roles</th>
            <th style="color:#ffffff;background-color:#808080;text-align:center" colspan="2">Ports</th>
            <th rowspan="2">Comment</th>
            <th rowspan="2">Pingable</th>
        </tr>
        <tr>
            <th>IPV4Address</th>
            <th>IPV6Address</th>
            <th>SchemaMaster</th>
            <th>DomainNamingMasterMaster</th>
            <th>PDCEmulator</th>
            <th>RIDMaster</th>
            <th>InfrastructureMaster</th>
            <th>LdapPort</th>
            <th>SslPort</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>ad.evotec.xyz</td>
            <td>AD2.ad.evotec.xyz</td>
            <td>ad.evotec.xyz</td>
            <td>192.168.240.192</td>
            <td></td>
            <td>True</td>
            <td>False</td>
            <td>KATOWICE-1</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>389</td>
            <td>636</td>
            <td></td>
            <td style="color:#ffffff;background-color:#008000">True</td>
        </tr>
        <tr>
            <td>ad.evotec.xyz</td>
            <td>AD1.ad.evotec.xyz</td>
            <td>ad.evotec.xyz</td>
            <td>192.168.240.189</td>
            <td></td>
            <td>True</td>
            <td>False</td>
            <td>KATOWICE-1</td>
            <td style="color:#ffffff;background-color:#008000">True</td>
            <td>True</td>
            <td style="color:#ffffff;background-color:#008000">True</td>
            <td style="color:#ffffff;background-color:#008000">True</td>
            <td>True</td>
            <td>389</td>
            <td>636</td>
            <td></td>
            <td style="color:#ffffff;background-color:#008000">True</td>
        </tr>
        <tr>
            <td>ad.evotec.xyz</td>
            <td>AD3.ad.evotec.xyz</td>
            <td>ad.evotec.xyz</td>
            <td>192.168.240.236</td>
            <td></td>
            <td>True</td>
            <td>False</td>
            <td>KATOWICE-2</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>389</td>
            <td>636</td>
            <td></td>
            <td style="color:#ffffff;background-color:#008000">True</td>
        </tr>
        <tr>
            <td>ad.evotec.pl</td>
            <td>ADPreview2019.ad.evotec.pl</td>
            <td>ad.evotec.xyz</td>
            <td>192.168.240.201</td>
            <td></td>
            <td>True</td>
            <td>False</td>
            <td>KATOWICE-2</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>389</td>
            <td>636</td>
            <td></td>
            <td style="color:#ffffff;background-color:#008000">True</td>
        </tr>
        <tr>
            <td>ad.evotec.pl</td>
            <td>DC1.ad.evotec.pl</td>
            <td>ad.evotec.xyz</td>
            <td>192.168.240.238</td>
            <td></td>
            <td>True</td>
            <td>False</td>
            <td>KATOWICE-1</td>
            <td>False</td>
            <td>False</td>
            <td style="color:#ffffff;background-color:#008000">True</td>
            <td style="color:#ffffff;background-color:#008000">True</td>
            <td>True</td>
            <td>389</td>
            <td>636</td>
            <td></td>
            <td style="color:#ffffff;background-color:#008000">True</td>
        </tr>
        <tr>
            <td>ad.evotec.pl</td>
            <td>ADRODC.ad.evotec.pl</td>
            <td>ad.evotec.xyz</td>
            <td>192.168.240.207</td>
            <td></td>
            <td>True</td>
            <td style="color:#000000;background-color:#ffff00">True</td>
            <td>GLIWICE</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>False</td>
            <td>389</td>
            <td>636</td>
            <td></td>
            <td style="color:#ffffff;background-color:#ff0000">False</td>
        </tr>
    </tbody>
</table>

What this Inline switch did is apply style for each Table Cell separately as required. It does this for headers with row spanning and column spanning and does this for styling. For this feature to work, it means that I have to rebuild table on the fly in PowerShell rather than relying on JavaScript at runtime. That means you may see some speed difference when using EmailTableCondition (Emailimo)/TableCondition (Dashimo)/New-HTMLTableCondition (PSWriteHTML) with and without Inline switch. Full code to design and send email is as below.

Import-Module Emailimo -Force

$DomainControllers = Get-WinADDomainControllers -TestAvailability

Email {
    EmailHeader {
        EmailFrom -Address 'reminder@evotec.pl'
        EmailTo -Addresses "kontakt@evotec.pl"
        EmailServer -Server 'smtp.office365.com' -UserName 'rpassword' -Password 'C:\Support\Important\Password-Evotec-Reminder.txt' -PasswordAsSecure -PasswordFromFile
        EmailOptions -Priority High -DeliveryNotifications Never
        EmailSubject -Subject 'This is a test email'
    }
    EmailBody -FontFamily 'Calibri' -Size 15 {
        EmailText -Text "Domain Controllers ", 'Status' -Color Blue, None
        EmailTable -DataTable $DomainControllers {
            EmailTableHeader -Names 'IPV4Address', 'IPV6Address' -Title 'Ip Addresses' -Alignment center -Color White -BackGroundColor Gray
            EmailTableHeader -Names 'SchemaMaster', 'PDCEmulator', 'RIDMaster', 'DomainNamingMasterMaster', 'InfrastructureMaster' -Title 'Roles' -Alignment center -Color White -BackGroundColor Gray
            EmailTableHeader -Names 'LdapPort', 'SslPort' -Title 'Ports' -Alignment center -Color White -BackGroundColor Gray
            EmailTableCondition -ComparisonType 'string' -Name 'SchemaMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'PDCEmulator' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'RIDMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'IsReadOnly' -Operator eq -Value 'True' -BackgroundColor Yellow -Color Black -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator ne -Value 'True' -BackgroundColor Red -Color White -Inline
        } -HideFooter

        EmailText -LineBreak

        EmailTextBox {
            'Kind regards,'
            'Evotec IT'
        }
    }
}

In just 35 lines, I was able to produce a nicely formatted email with readable code. Something that wasn't possible before.

Inline Table Conditional Formatting in PSWriteHTML

As mentioned above, Emailimo, Dashimo, and PSWriteHTML share the same building structure with just different syntax. This means with a slight change to syntax you can get the same thing in Dashimo or PSWriteHTML directly.

$DomainControllers = Get-WinADDomainControllers -TestAvailability

New-HTML -UseCssLinks -UseJavaScriptLinks {
    New-HTMLTable -DataTable $DomainControllers {
        New-HTMLTableHeader -Names 'IPV4Address', 'IPV6Address' -Title 'Ip Addresses' -Alignment center -Color White -BackGroundColor Gray
        New-HTMLTableHeader -Names 'SchemaMaster', 'PDCEmulator', 'RIDMaster', 'DomainNamingMasterMaster', 'InfrastructureMaster' -Title 'Roles' -Alignment center -Color White -BackGroundColor Gray
        New-HTMLTableHeader -Names 'LdapPort', 'SslPort' -Title 'Ports' -Alignment center -Color White -BackGroundColor Gray
        New-HTMLTableCondition -ComparisonType 'string' -Name 'SchemaMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'PDCEmulator' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'RIDMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'IsReadOnly' -Operator eq -Value 'True' -BackgroundColor Yellow -Color Black -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator ne -Value 'True' -BackgroundColor Red -Color White -Inline
    } -HideFooter
} -FilePath $PSScriptRoot\TestMyHTML.html -ShowHTML -TitleText 'My test'

Similar code gives you somewhat similar results. Of course, the difference is that by default, PSWriteHTML generates HTML with JavaScript enabled. This will work fine in Chrome, New Edge or Firefox, giving you slightly more features that I've already covered in earlier blogs such as export to Excel, PDF, or advanced sorting. There's also somewhat different visual output since it's styled with original DataTables.net colors. New-HTMLTable contains additional switch Simplify. The purpose of this switch is that all that JavaScript functionality is disabled and you get what you would usually get when using Emailimo.

$DomainControllers = Get-WinADDomainControllers -TestAvailability

New-HTML -UseCssLinks -UseJavaScriptLinks {
    New-HTMLTable -DataTable $DomainControllers {
        New-HTMLTableHeader -Names 'IPV4Address', 'IPV6Address' -Title 'Ip Addresses' -Alignment center -Color White -BackGroundColor Gray
        New-HTMLTableHeader -Names 'SchemaMaster', 'PDCEmulator', 'RIDMaster', 'DomainNamingMasterMaster', 'InfrastructureMaster' -Title 'Roles' -Alignment center -Color White -BackGroundColor Gray
        New-HTMLTableHeader -Names 'LdapPort', 'SslPort' -Title 'Ports' -Alignment center -Color White -BackGroundColor Gray
        New-HTMLTableCondition -ComparisonType 'string' -Name 'SchemaMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'PDCEmulator' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'RIDMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'IsReadOnly' -Operator eq -Value 'True' -BackgroundColor Yellow -Color Black -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
        New-HTMLTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator ne -Value 'True' -BackgroundColor Red -Color White -Inline
    } -HideFooter -Simplify
} -FilePath $PSScriptRoot\TestMyHTML.html -ShowHTML -TitleText 'My test'

This Simplify functionality may seem like a useless gimmick, but it isn't if you take into consideration the next feature I wanted to show you.

New-HTMLTableContent - New command for manipulating style and content of HTML Tables

New-HTMLTableCondition is excellent functionality which allows you to quickly and easily style your content based on conditions without doing any work by yourself. This functionality is based on New-HTMLTableContent function, which I want to introduce in this part of the blog. This function is a bit like New-HTMLTableHeader. It allows you to style or merge the content of a table. Let's take a look at an example below.

Import-Module .\PSWriteHTML.psd1 -Force

$Properties = @(
    'Name'
    'Id'
    'PriorityClass'
    'FileVersion'
    'HandleCount'
    'WorkingSet'
    'PagedMemorySize'
    'PrivateMemorySize'
    'VirtualMemorySize'
    'TotalProcessorTime'
)
$ProcessesAll = Get-Process | Select-Object -First 10
$Processes = $ProcessesAll | Select-Object -First 10 -Property $Properties

New-HTML -TitleText 'Title' -UseCssLinks:$true -UseJavaScriptLinks:$true -FilePath $PSScriptRoot\Example24_01.html -ShowHTML {
    New-HTMLContent -HeaderText '0 section' {
        New-HTMLPanel {
            New-HTMLTable -DataTable $Processes -HideFooter -ScrollCollapse {
                New-HTMLTableContent -Names 'Name' -RowIndex 5 -BackGroundColor Blue
                New-HTMLTableContent -Names 'Name' -RowIndex 1 -BackGroundColor Yellow
                New-HTMLTableContent -Names 'HandleCount' -RowIndex 1 -BackGroundColor Yellow
                New-HTMLTableContent -ColumnIndex 7 -RowIndex 4 -BackGroundColor Gold -Color Blue -FontStyle italic
            }
        }
    }
}

As you can see this time I'm operating on Column Names and Row Index. You can also operate on Column Index instead of Column Name if it's something you prefer. And then you can simply tell it to apply any styling you want. From colors, to making it bold or italic. Up to you.

Nice right? But that's not all. You can also use it to replace text within table.

Import-Module .\PSWriteHTML.psd1 -Force

$Properties = @(
    'Name'
    'Id'
    'PriorityClass'
    'FileVersion'
    'HandleCount'
    'WorkingSet'
    'PagedMemorySize'
    'PrivateMemorySize'
    'VirtualMemorySize'
    'TotalProcessorTime'
)
$ProcessesAll = Get-Process | Select-Object -First 10
$Processes = $ProcessesAll | Select-Object -First 10 -Property $Properties

New-HTML -TitleText 'Title' -UseCssLinks:$true -UseJavaScriptLinks:$true -FilePath $PSScriptRoot\Example24_01.html -ShowHTML {
    New-HTMLContent -HeaderText '0 section' {
        New-HTMLPanel {
            New-HTMLTable -DataTable $Processes -HideFooter -ScrollCollapse {
                New-HTMLTableContent -Names 'Name' -RowIndex 5 -BackGroundColor Blue
                New-HTMLTableContent -Names 'Name' -RowIndex 1 -BackGroundColor Yellow
                New-HTMLTableContent -Names 'HandleCount' -RowIndex 1 -BackGroundColor Yellow
                New-HTMLTableContent -ColumnIndex 7 -RowIndex 4 -BackGroundColor Gold -Color Blue -FontStyle italic -Text "I HAVE REPLACED THIS" -FontSize 15
            }
        }
    }
}

That's done by using Text parameter. Easy right? Useful? Well, it has it's use cases, which I will show you in a second. Take a look at example below where I'm replacing Text that spans across 2 rows and 3 columns.

Cool right? Of course, in case of this example, it's useless, but you can use this functionality in Emails or Reports as you want.

Import-Module .\PSWriteHTML.psd1 -Force

$Properties = @(
    'Name'
    'Id'
    'PriorityClass'
    'FileVersion'
    'HandleCount'
    'WorkingSet'
    'PagedMemorySize'
    'PrivateMemorySize'
    'VirtualMemorySize'
    'TotalProcessorTime'
)
$ProcessesAll = Get-Process | Select-Object -First 10
$Processes = $ProcessesAll | Select-Object -First 10 -Property $Properties

New-HTML -TitleText 'Title' -UseCssLinks:$true -UseJavaScriptLinks:$true -FilePath $PSScriptRoot\Example24_01.html -ShowHTML {
    New-HTMLContent -HeaderText '0 section' {
        New-HTMLPanel {
            New-HTMLTable -DataTable $Processes -HideFooter -ScrollCollapse {
                New-HTMLTableContent -Names 'Name' -RowIndex 5 -BackGroundColor Blue
                New-HTMLTableContent -Names 'Name' -RowIndex 1 -BackGroundColor Yellow
                New-HTMLTableContent -Names 'HandleCount' -RowIndex 1 -BackGroundColor Yellow
                New-HTMLTableContent -ColumnIndex 7,8,9 -RowIndex 4,5 -BackGroundColor Gold -Color Blue -FontStyle italic -Text "I HAVE REPLACED THIS" -FontSize 15 -Alignment center
            } -Simplify
        }
    }
}

It's important to notice two things. Replacement line shows you how to do merging and styling, but also how I've used Simplify parameter for New-HTMLTable. It's not there by accident. When you enable merging within a table JavaScript functionality related to sorting, filtering, resizing is broken because it would need to consider that some columns/rows are now joined together which is not something that can easily be fixed. Until DataTables.net adds this functionality in their code, you need to use Simplify switch if you want to utilize merging functionality within table content. Text replacement, styling all that works without that switch. Just joining is affected. Of course, this functionality is identical in Emailimo or Dashimo.

You can use EmailTableContent or TableContent to apply to style in Dashimo or Emailimo. In emailimo, it even makes more sense to merge cells.

Import-Module Emailimo -Force

$DomainControllers = Get-WinADDomainControllers -TestAvailability

$Data = @(
    [PSCustomObject] @{ Name = 'Test 1'; 'OtherData' = 'Special Values'; 'Value' = 57 }
    [PSCustomObject] @{ Name = 'Test 1'; 'OtherData' = 'Special Values'; 'Value' = 105 }
    [PSCustomObject] @{ Name = 'Test 1'; 'OtherData' = 'Special Values'; 'Value' = 20 }
    [PSCustomObject] @{ Name = 'Test 1'; 'OtherData' = 'Special Values'; 'Value' = 11 + 20 + 105 + 57 }
)

Email {
    EmailHeader {
        EmailFrom -Address 'reminder@evotec.pl'
        EmailTo -Addresses "kontakt@evotec.pl"
        EmailServer -Server 'smtp.office365' -UserName 'rpassword' -Password 'C:\Support\Important\Password-Evotec-Reminder.txt' -PasswordAsSecure -PasswordFromFile
        EmailOptions -Priority High -DeliveryNotifications Never
        EmailSubject -Subject 'This is a test email'
    }
    EmailBody -FontFamily 'Calibri' -Size 15 {
        EmailText -Text "Hello ", $UserNotify, "," -Color None, Blue, None -Verbose -LineBreak

        EmailText -Text "Domain Controllers ", 'Status' -Color Blue, None
        EmailTable -DataTable $DomainControllers {
            EmailTableHeader -Names 'IPV4Address', 'IPV6Address' -Title 'Ip Addresses' -Alignment center -Color White -BackGroundColor Gray
            EmailTableHeader -Names 'SchemaMaster', 'PDCEmulator', 'RIDMaster', 'DomainNamingMasterMaster', 'InfrastructureMaster' -Title 'Roles' -Alignment center -Color White -BackGroundColor Gray
            EmailTableHeader -Names 'LdapPort', 'SslPort' -Title 'Ports' -Alignment center -Color White -BackGroundColor Gray
            EmailTableCondition -ComparisonType 'string' -Name 'SchemaMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'PDCEmulator' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'RIDMaster' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'IsReadOnly' -Operator eq -Value 'True' -BackgroundColor Yellow -Color Black -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator eq -Value 'True' -BackgroundColor Green -Color White -Inline
            EmailTableCondition -ComparisonType 'string' -Name 'Pingable' -Operator ne -Value 'True' -BackgroundColor Red -Color White -Inline
        } -HideFooter

        EmailText -LineBreak

        EmailTable -DataTable $Data {
            EmailTableContent -RowIndex 4 -ColumnIndex 1, 2 -Text 'Summary' -Color Black -BackGroundColor Gray
        } -HideFooter

        EmailText -LineBreak

        EmailTextBox {
            'Kind regards,'
            'Evotec IT'
        }
    }
} -AttachSelf

Since JavaScript in Email is disabled merging doesn't require you to define Simplify parameter. However, keep in mind that when you use AttachSelf switch (as mentioned in my other blog) which attaches Email Content as an attachment – this attachment is JS Enabled. That means when you open up it in Chrome, and you've used merging without Simplify parameter for your tables, it will be broken JS just like I've described above. For small tables, you may not notice a problem, but for larger ones, the functionality you expected will not be there. So just a fair warning. Otherwise, be my guest and use this as required.

Mix and match Conditional Formatting, Header and Content manipulation

You can, of course, mix and match all the options together. Having New-HTMLTableHeader, New-HTMLTableCondition, and New-HTMLTableContent all applying their styles and changes as you need to. While the tables below don't look pretty, I just wanted to show you that it's not a problem to have a lot of additional formatting. And since we don't have a massive amount of data to process on my computer, it's still around 2 seconds.

Import-Module PSWriteHTML -Force

$Properties = @(
    'Name'
    'Id'
    'PriorityClass'
    'FileVersion'
    'HandleCount'
    'WorkingSet'
    'PagedMemorySize'
    'PrivateMemorySize'
    'VirtualMemorySize'
    'TotalProcessorTime'
)
$ProcessesAll = Get-Process | Select-Object -First 10
$Processes = $ProcessesAll | Select-Object -First 10 -Property $Properties

New-HTML -TitleText 'Title' -UseCssLinks:$true -UseJavaScriptLinks:$true -FilePath $PSScriptRoot\Example24.html -ShowHTML {
    New-HTMLContent -HeaderText 'Section 1' {
        New-HTMLContainer {
            New-HTMLPanel {
                New-HTMLTable -DataTable $Processes -HideFooter -ScrollCollapse {

                    New-HTMLTableHeader -Names 'Name', 'ID' -Title 'Process Information' -Color Red -FontWeight lighter -Alignment left -BackGroundColor LightBlue

                    New-HTMLTableHeader -Names 'PagedMemorySize', 'PrivateMemorySize', 'VirtualMemorySize' -Title 'Memory' -Color White -BackGroundColor Blue
                    New-HTMLTableHeader -Names 'Name' -BackGroundColor Red -Color WhiteSmoke
                    New-HTMLTableHeader -Names 'Id' -BackGroundColor Blue -Color White
                    New-HTMLTableHeader -Names 'PriorityClass', 'FileVersion', 'HandleCount' -BackGroundColor Gold -Color White
                    New-HTMLTableHeader -BackGroundColor Green -Color White -Title 'Full Title'
                    New-HTMLTableCondition -Name 'HandleCount' -ComparisonType number -Operator gt -Value 500 -BackgroundColor Gray -Color White
                    New-HTMLTableCondition -Name 'FileVersion' -ComparisonType string -Operator eq -Value '1.36.1' -BackgroundColor Gold -Color White -FontWeight bold -Alignment center -TextDecoration line-through
                    New-HTMLTableContent -Names 'Name' -RowIndex 5 -BackGroundColor Blue
                    New-HTMLTableContent -Names 'Name' -RowIndex 1 -BackGroundColor Yellow
                    New-HTMLTableContent -Names 'HandleCount' -RowIndex 1 -BackGroundColor Yellow
                }
            }
            New-HTMLPanel {
                New-HTMLTable -DataTable $Processes -HideFooter -Simplify {
                    New-HTMLTableContent -ColumnIndex 2, 3, 4, 5 -RowIndex 7, 6 -Text 'Replace 4 columns, over 2 rows' -Alignment center -Color Green -FontWeight bold -BackGroundColor Yellow
                }
            }
        }
    }
    New-HTMLContent -HeaderText 'Section 2' {
        New-HTMLPanel {
            New-HTMLTable -DataTable $Processes -HideFooter -ScrollCollapse {

                New-HTMLTableHeader -Names 'Name', 'ID' -Title 'Process Information' -Color Red -FontWeight lighter -Alignment left -BackGroundColor LightBlue
                New-HTMLTableHeader -Names 'PagedMemorySize', 'PrivateMemorySize', 'VirtualMemorySize' -Title 'Memory' -Color White -BackGroundColor Blue
                New-HTMLTableHeader -Names 'Name' -BackGroundColor Red -Color WhiteSmoke
                New-HTMLTableHeader -Names 'Id' -BackGroundColor Blue -Color White
                New-HTMLTableHeader -Names 'PriorityClass', 'FileVersion', 'HandleCount' -BackGroundColor Gold -Color White
                New-HTMLTableHeader -BackGroundColor Green -Color White -Title 'Full Title'
                New-HTMLTableCondition -Name 'HandleCount' -ComparisonType number -Operator gt -Value 500 -BackgroundColor Gray -Color White
                New-HTMLTableCondition -Name 'FileVersion' -ComparisonType string -Operator eq -Value '1.36.1' -BackgroundColor Gold -Color White -FontWeight bold -Alignment center -TextDecoration line-through

                New-HTMLTableContent -RowIndex 5, 3 -BackGroundColor Blue -Color White

                New-HTMLTableContent -ColumnName 'Name', 'PagedMemorySize' -BackGroundColor Gold -Color Green

                New-HTMLTableContent -ColumnIndex 5, 2 -BackGroundColor Green -Color White

                New-HTMLTableContent -ColumnIndex 2 -RowIndex 2 -Text 'Test' -Alignment center -Color Green -FontWeight bold -BackGroundColor Yellow
                New-HTMLTableContent -ColumnIndex 2 -RowIndex 5 -Text 'Test 1' -Alignment center -Color Green -FontWeight bold -BackGroundColor Yellow

                New-HTMLTableContent -ColumnIndex 2, 3, 4, 5 -RowIndex 7, 6 -Text 'Replace 4 columns' -Alignment center -Color Green -FontWeight bold -BackGroundColor Yellow


                New-HTMLTableContent -Names 'Name' -RowIndex 5 -BackGroundColor Blue
                New-HTMLTableContent -Names 'Name' -RowIndex 1 -BackGroundColor Yellow
                New-HTMLTableContent -Names 'HandleCount' -RowIndex 1 -BackGroundColor Yellow -FontStyle italic
                New-HTMLTableContent -Names 'HandleCount' -RowIndex 2 -BackGroundColor Blue -Color White -FontStyle italic
                New-HTMLTableContent -ColumnIndex 8 -RowIndex 2 -BackGroundColor Blue -Color White -FontStyle italic
                New-HTMLTableContent -ColumnIndex 3 -RowIndex 6 -BackGroundColor Blue -Color White -FontStyle italic
                New-HTMLTableContent -ColumnIndex 1 -RowIndex 4 -BackGroundColor Blue -Color White -FontStyle italic

                New-HTMLTableCondition -Name 'FileVersion' -ComparisonType string -Operator eq -Value '1.36.1' -BackgroundColor Gold -Color White -FontWeight bold -Alignment center -TextDecoration line-through -Inline
                New-HTMLTableCondition -Name 'FileVersion' -ComparisonType string -Operator eq -Value '10.1905.30.0' -BackgroundColor Green -Color White -FontWeight bold -Alignment center -TextDecoration line-through -Inline -Row
                New-HTMLTableCondition -Name 'FileVersion' -ComparisonType string -Operator eq -Value '1.36.1' -BackgroundColor Red -Color White -FontWeight bold -Inline -row
                New-HTMLTableCondition -Name 'Name' -Operator ne -Value 'AppVShNotify' -BackgroundColor Red -Color White -Inline -row
                New-HTMLTableCondition -ComparisonType 'number' -Name 'Id' -Operator gt -Value 15000 -BackgroundColor Green -Color White -Inline #-row
                New-HTMLTableCondition -ComparisonType 'number' -Name 'Id' -Operator lt -Value 15000 -BackgroundColor Red -Color White -Inline #-row
                New-HTMLTableCondition -ComparisonType string -Name 'Name' -Operator eq -Value 'Code' -BackgroundColor blue -Color White -Inline -row
            }
        }
    }
}

As I've explained before, when you use Inline switch, it will impact generation time. For smaller tables, it shouldn't be noticeable, for larger ones it may add a few seconds here and there depending on what you will be doing if you decide to apply new formatting for every single row it has to go and fix style per each Table Cell. You can see for yourself how the last table looks if you apply a lot of formatting to it.

<table id="DT-ddCbWNYX" class="display compact">
    <thead>
        <tr>
            <th style="color:#ffffff;background-color:#008000" colspan="10">Full Title</th>
        </tr>
        <tr>
            <th style="color:#ff0000;background-color:#add8e6;text-align:left;font-weight:lighter"
                colspan="2">Process Information</th>
            <th style="color:#ffffff;background-color:#ffd700" rowspan="2">PriorityClass
            </th>
            <th style="color:#ffffff;background-color:#ffd700" rowspan="2">FileVersion</th>
            <th style="color:#ffffff;background-color:#ffd700" rowspan="2">HandleCount</th>
            <th rowspan="2">WorkingSet</th>
            <th style="color:#ffffff;background-color:#0000ff" colspan="3">Memory</th>
            <th rowspan="2">TotalProcessorTime</th>
        </tr>
        <tr>
            <th style="color:#f5f5f5;background-color:#ff0000">Name</th>
            <th style="color:#ffffff;background-color:#0000ff">Id</th>
            <th>PagedMemorySize</th>
            <th>PrivateMemorySize</th>
            <th>VirtualMemorySize</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000">1Password</td>
            <td style="color:#ffffff;background-color:#008000">17180</td>
            <td style="color:#ffffff;background-color:#ff0000">Normal</td>
            <td style="color:#ffffff;background-color:#ff0000">7.3.684</td>
            <td style="color:#ffffff;background-color:#ff0000">762</td>
            <td style="color:#ffffff;background-color:#ff0000">11976704</td>
            <td style="color:#ffffff;background-color:#ff0000">44621824</td>
            <td style="color:#ffffff;background-color:#ff0000">44621824</td>
            <td style="color:#ffffff;background-color:#ff0000">296759296</td>
            <td style="color:#ffffff;background-color:#ff0000">00:00:01.5000000</td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000">aesm_service</td>
            <td style="color:#ffffff;background-color:#008000">25340</td>
            <td style="color:#ffffff;background-color:#ff0000"></td>
            <td style="color:#ffffff;background-color:#ff0000"></td>
            <td style="color:#ffffff;background-color:#ff0000">189</td>
            <td style="color:#ffffff;background-color:#ff0000">3497984</td>
            <td style="color:#ffffff;background-color:#ff0000">2482176</td>
            <td style="color:#ffffff;background-color:#ff0000">2482176</td>
            <td style="color:#ffffff;background-color:#ff0000">94785536</td>
            <td style="color:#ffffff;background-color:#ff0000"></td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000">ApplicationFrameHost</td>
            <td style="color:#ffffff;background-color:#ff0000">2020</td>
            <td style="color:#ffffff;background-color:#ff0000">Normal</td>
            <td style="color:#ffffff;background-color:#ff0000">10.0.18362.1
                (WinBuild.160101.0800)</td>
            <td style="color:#ffffff;background-color:#ff0000">488</td>
            <td style="color:#ffffff;background-color:#ff0000">9154560</td>
            <td style="color:#ffffff;background-color:#ff0000">23728128</td>
            <td style="color:#ffffff;background-color:#ff0000">23728128</td>
            <td style="color:#ffffff;background-color:#ff0000">271568896</td>
            <td style="color:#ffffff;background-color:#ff0000">00:00:00.5937500</td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000">audiodg</td>
            <td style="color:#ffffff;background-color:#008000">30916</td>
            <td style="color:#ffffff;background-color:#ff0000"></td>
            <td style="color:#ffffff;background-color:#ff0000"></td>
            <td style="color:#ffffff;background-color:#ff0000">177</td>
            <td style="color:#ffffff;background-color:#ff0000">12255232</td>
            <td style="color:#ffffff;background-color:#ff0000">6754304</td>
            <td style="color:#ffffff;background-color:#ff0000">6754304</td>
            <td style="color:#ffffff;background-color:#ff0000">86020096</td>
            <td style="color:#ffffff;background-color:#ff0000">00:00:00.7968750</td>
        </tr>
        <tr>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                Calculator</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                2748</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                Normal</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                10.1905.30.0</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                575</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                548864</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                36745216</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                36745216</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                548401152</td>
            <td
                style="color:#ffffff;background-color:#008000;text-align:center;text-decoration:line-through;font-weight:bold">
                00:00:00.2343750</td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Code</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">6644</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Normal</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1.36.1</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">236</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">8126464</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">28364800
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">28364800
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">413822976
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">
                00:00:00.1718750</td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Code</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">9332</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Normal</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1.36.1</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1257</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">70463488
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">63787008
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">63787008
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">684625920
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">
                00:19:37.2656250</td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Code</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">11648</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Normal</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1.36.1</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">389</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">17711104
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">186875904
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">186875904
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1712168960
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">
                00:00:05.0781250</td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Code</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">13468</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Normal</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1.36.1</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">399</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">18501632
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">248168448
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">248168448
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1771180032
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">
                00:01:04.2968750</td>
        </tr>
        <tr>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Code</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">15888</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">Normal</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1.36.1</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">407</td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">329633792
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">430379008
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">430379008
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">1986240512
            </td>
            <td style="color:#ffffff;background-color:#ff0000;font-weight:bold">
                00:02:21.5625000</td>
        </tr>
    </tbody>
</table>
New-HTMLToast - simple message feature

While working on the new version I've updated how I create “Toast” messages, I've not written about this feature anywhere, but it was used as part of Statusimo module. I've rewritten it and now added the ability to use any of 1000+ icons, and choose colors for the left bar, right bar, header text, text giving you a personal touch. Not sure how useful it will be in your scenarios, but it's there if you need it.

The code is straightforward. If you know how to use Panels/Sections and Tables put a toast inside one of those and you should be fine.

$Processes = Get-Process | Select-Object -First 20

New-HTML -TitleText 'Title' -UseCssLinks -UseJavaScriptLinks -FilePath $PSScriptRoot\Example25.html {
    New-HTMLContent -Invisible {
        New-HTMLPanel -Invisible {
            New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconRegular address-card
        }
        New-HTMLPanel -Invisible {
            New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconColor DarkGrey -BarColorLeft ForestGreen -TextColor Gainsboro -IconBrands 500px
        }
    }
    New-HTMLContent -Invisible {
        New-HTMLTable -DataTable $Processes -HideFooter
    }
    New-HTMLPanel -Invisible {
        New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconColor AliceBlue -BarColorLeft Grey -TextHeaderColor Gold -IconRegular eye
        New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconBrands app-store
        New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconRegular surprise
        New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconSolid bell
        New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconBrands cloudsmith
        New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconBrands accessible-icon
        New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -IconBrands accusoft -BarColorRight DarkTurquoise
    }
} -ShowHTML

Finally, I wanted also to let you know about two other features PSWriteHTML is capable of and something that Statusimo is currently using. Those are Status Messages and Timeline. You can see the StatusItem buttons under the Current Status section and Timeline is visible under Past Incidents section. Their current state is “it works,” but I don't like how it's built and how it looks so you may expect those features to be changed/expanded.

Code below is all it takes to create Status Page as above. Feel free to create your own Status Pages or use Statusimo the way it was written.

New-HTML -TitleText 'Services Status' -UseCssLinks -UseJavaScriptLinks {

    New-HTMLSection -Invisible {
        New-HTMLContainer -Width '900px' -Margin 'auto' {
            New-HTMLPanel -Invisible {
                New-HTMLToast -TextHeader 'Information' -Text 'Everything is running smoothly!' -BarColorLeft Blue -IconSolid info-circle -IconColor Blue
            }

            New-HTMLHeading -Heading h1 -HeadingText 'Current Status'

            New-HTMLPanel -Invisible {
                New-HTMLStatus {
                    New-HTMLStatusItem -ServiceName 'Active Directory' -ServiceStatus 'Operational' -Icon Good -Percentage '100%'
                    New-HTMLStatusItem -ServiceName 'Github' -ServiceStatus 'Operational' -Icon Good -Percentage '100%'
                    New-HTMLStatusItem -ServiceName 'Hyper-V' -ServiceStatus 'Non-functional' -Icon Dead -Percentage '0%'
                    New-HTMLStatusItem -ServiceName 'Active Directory' -ServiceStatus 'Operational' -Icon Good -Percentage '100%'
                    New-HTMLStatusItem -ServiceName 'Azure' -ServiceStatus 'Working on it' -Icon Bad -Percentage '70%'
                    New-HTMLStatusItem -ServiceName 'Twitter' -ServiceStatus 'Who knows?!' -Icon Bad -Percentage '30%'
                }
            }

            New-HTMLHeading -Heading h1 -HeadingText 'Scheduled Maintenance'

            New-HTMLPanel -Invisible {
                New-HTMLToast -TextHeader 'Maintenance' -Text "We've planned maintenance on 24th of January 2020. It will last 30 hours." -BarColorLeft OrangeRed -IconSolid info-circle -IconColor OrangeRed
            }


            New-HTMLHeading -Heading h1 -HeadingText 'Incidents per day'

            New-HTMLPanel -Invisible {


                $Data = foreach ($Element in 30..0) {
                    Get-Random -Minimum 0 -Maximum 5
                }
                $DataName = "Incidents"
                $DataCategories = foreach ($Element in 30..0) {
                    (Get-Date).AddDays(-$Element).ToShortDateString()
                }
                New-HTMLChart -Title 'Incidents per day' -TitleAlignment left {
                    New-ChartCategory -Name $DataCategories
                    New-ChartLine -Name $DataName -Value $Data
                }
            }

            New-HTMLHeading -Heading h1 -HeadingText 'Past Incidents'

            New-HTMLPanel -Invisible {
                New-HTMLTimeline {
                    New-HTMLTimelineItem -HeadingText 'Azure AD is down' -Text "We have huge problems" -Date (Get-Date).AddDays(-1)
                    New-HTMLTimelineItem -HeadingText 'Azure AD ...' -Text "We have huge problems" -Date (Get-Date).AddDays(-2)
                    New-HTMLTimelineItem -HeadingText 'AD just died' -Text "We have huge problems" -Date (Get-Date).AddDays(-3)
                    New-HTMLTimelineItem -HeadingText 'Twitter' -Text "We're very soorrry! It just won't work!" -Date (Get-Date).AddDays(-4)
                    New-HTMLTimelineItem -HeadingText 'Twitter' -Text "We're very soorrry! It just won't work!" -Date (Get-Date).AddDays(-4)
                    New-HTMLTimelineItem -HeadingText 'Twitter' -Text "We're very soorrry! It just won't work!" -Date (Get-Date).AddDays(-4)
                    New-HTMLTimelineItem -HeadingText 'Twitter' -Text "We're very soorrry! It just won't work!" -Date (Get-Date).AddDays(-5)
                    New-HTMLTimelineItem -HeadingText 'Twitter' -Text "We're very soorrry! It just won't work!" -Date (Get-Date).AddDays(-6)
                    New-HTMLTimelineItem -HeadingText 'Twitter' -Text "We're very soorrry! It just won't work!" -Date (Get-Date).AddDays(-7)
                }
            }
        }
    }
} -FilePath $PSScriptRoot\StatusPage04.html -ShowHTML
Using PSWriteHTML, Dashimo, Statusimo or Emailimo as PowerShell Module

For easy use and installation, all modules are available from PowerShellGallery. Installing it is as easy as it gets. Keep in mind that when you install Emailimo, you get PSWriteHTML installed by default, so you don't have to install it separately. Same goes for Dashimo or Statusimo.

Install-Module PSWriteHTML -AllowClobber -Force
Install-Module Dashimo -AllowClobber -Force
Install-Module Statusimo -AllowClobber -Force
Install-Module Emailimo -AllowClobber -Force

Code as always is stored on GitHub and is free to use and take.

This post was last modified on August 5, 2019 21:51

Przemyslaw Klys

System Architect with over 14 years of experience in the IT field. Skilled, among others, in Active Directory, Microsoft Exchange and Office 365. Profoundly interested in PowerShell. Software geek.

Share
Published by
Przemyslaw Klys

Recent Posts

Upgrade Azure Active Directory Connect fails with unexpected error

Today, I made the decision to upgrade my test environment and update the version of…

2 months ago

Mastering Active Directory Hygiene: Automating Stale Computer Cleanup with CleanupMonster

Have you ever looked at your Active Directory and wondered, "Why do I still have…

3 months ago

Active Directory Replication Summary to your Email or Microsoft Teams

Active Directory replication is a critical process that ensures the consistent and up-to-date state of…

7 months ago

Syncing Global Address List (GAL) to personal contacts and between Office 365 tenants with PowerShell

Hey there! Today, I wanted to introduce you to one of the small but excellent…

12 months ago

Active Directory Health Check using Microsoft Entra Connect Health Service

Active Directory (AD) is crucial in managing identities and resources within an organization. Ensuring its…

1 year ago

Seamless HTML Report Creation: Harness the Power of Markdown with PSWriteHTML PowerShell Module

In today's digital age, the ability to create compelling and informative HTML reports and documents…

1 year ago