Adding Charts to a Report Module
AsBuiltReport.Chart is an optional PowerShell module that adds chart generation capabilities to AsBuiltReport report modules. It provides five chart types — pie, bar, stacked bar, single stacked bar, and signal — and integrates directly with the PScribo document framework used by AsBuiltReport.
Charts are generated in memory as base64-encoded images and embedded directly into the report output using PScribo's Image cmdlet. No intermediate files are written to disk.
Prerequisite Reading
This guide assumes you are already familiar with creating AsBuiltReport report modules. If not, read the Creating a Report Module guide first.
Installation
Install AsBuiltReport.Chart from the PowerShell Gallery:
Declaring the Dependency
Add AsBuiltReport.Chart to the RequiredModules array in your module manifest (.psd1). This ensures the module is automatically installed when your report module is installed.
RequiredModules = @(
@{
ModuleName = 'AsBuiltReport.Core'
ModuleVersion = '1.6.1'
}
@{
ModuleName = 'AsBuiltReport.Chart'
ModuleVersion = '0.3.2'
}
)
How Charts Are Embedded
All chart cmdlets accept a -Format base64 parameter that returns the chart as a base64-encoded string rather than writing a file to disk. This string is then passed directly to PScribo's Image cmdlet.
# Generate chart as base64 string
$chartFileItem = New-PieChart -Title 'VM Power States' `
-Values $chartValues `
-Labels $chartLabels `
-Format base64 `
-Width 600 -Height 400
# Embed the chart in the PScribo report
if ($chartFileItem) {
Image -Text 'VM Power State Distribution' -Align 'Center' -Percent 100 -Base64 $chartFileItem
}
The Image cmdlet is provided by PScribo and is available inside any Section block in your report module.
Data Preparation
Chart cmdlets require their input arrays to be explicitly typed. Always cast labels to [string[]] and values to [double[]] before passing them to a chart cmdlet.
$sampleData = [ordered]@{
'Success' = 85
'Warning' = 12
'Failed' = 3
}
$chartLabels = [string[]]$sampleData.Keys
$chartValues = [double[]]$sampleData.Values
Chart Types
Pie Chart
Use New-PieChart to show proportional distribution across categories — for example, VM power states, job results, or license usage by type.
$sampleData = [ordered]@{
'Powered On' = ($VMs | Where-Object { $_.PowerState -eq 'PoweredOn' } | Measure-Object).Count
'Powered Off' = ($VMs | Where-Object { $_.PowerState -eq 'PoweredOff' } | Measure-Object).Count
'Suspended' = ($VMs | Where-Object { $_.PowerState -eq 'Suspended' } | Measure-Object).Count
}
$chartLabels = [string[]]$sampleData.Keys
$chartValues = [double[]]$sampleData.Values
$chartFileItem = New-PieChart `
-Title ' ' `
-Values $chartValues `
-Labels $chartLabels `
-EnableCustomColorPalette `
-CustomColorPalette @('#DFF0D0', '#FFF3C4', '#FECDD1') `
-Width 600 -Height 400 `
-Format base64 `
-EnableLegend `
-LegendOrientation Vertical `
-LegendAlignment UpperRight `
-TitleFontBold `
-TitleFontSize 16
Bar Chart
Use New-BarChart to compare values across discrete categories — for example, backup job results by status, or compliance check outcomes.
$sampleData = [ordered]@{
'Success' = ($Jobs | Where-Object { $_.LatestStatus -eq 'Success' } | Measure-Object).Count
'Warning' = ($Jobs | Where-Object { $_.LatestStatus -eq 'Warning' } | Measure-Object).Count
'Failed' = ($Jobs | Where-Object { $_.LatestStatus -eq 'Failed' } | Measure-Object).Count
'None' = ($Jobs | Where-Object { $_.LatestStatus -eq 'None' } | Measure-Object).Count
}
$chartLabels = [string[]]$sampleData.Keys
$chartValues = [double[]]$sampleData.Values
$chartFileItem = New-BarChart `
-Title 'Backup Job Results' `
-Values $chartValues `
-Labels $chartLabels `
-LabelXAxis 'Status' `
-LabelYAxis 'Job Count' `
-EnableCustomColorPalette `
-CustomColorPalette @('#DFF0D0', '#FFF3C4', '#FECDD1', '#ADACAF') `
-Width 600 -Height 400 `
-Format base64 `
-EnableLegend `
-LegendOrientation Horizontal `
-LegendAlignment UpperCenter `
-AxesMarginsTop 0.5 `
-TitleFontBold `
-TitleFontSize 16
Stacked Bar Chart
Use New-StackedBarChart when each bar is composed of multiple segments — for example, repository used space vs. free space, or resource allocation across multiple hosts.
The -Values parameter expects an array of arrays: one inner array per bar, with each element representing a segment value.
$sampleData = $Repositories | Select-Object Name, UsedSpacePercent, FreeSpacePercent
$chartLabels = [string[]]$sampleData.Name
$chartCategories = @('Used (%)', 'Free (%)')
$chartUsedValues = [double[]]$sampleData.UsedSpacePercent
$chartFreeValues = [double[]]$sampleData.FreeSpacePercent
# Build array-of-arrays: one inner array per bar (one per repository)
$chartValues = @()
foreach ($i in 0..($chartLabels.Count - 1)) {
$chartValues += , @($chartUsedValues[$i], $chartFreeValues[$i])
}
$chartFileItem = New-StackedBarChart `
-Title 'Repository Space Utilisation' `
-Values $chartValues `
-Labels $chartLabels `
-LegendCategories $chartCategories `
-EnableCustomColorPalette `
-CustomColorPalette @('#FECDD1', '#DFF0D0') `
-Width 600 -Height 600 `
-Format base64 `
-AreaOrientation Horizontal `
-LabelXAxis 'Space (%)' `
-LabelYAxis 'Repository' `
-EnableLegend `
-LegendOrientation Horizontal `
-LegendAlignment UpperCenter `
-AxesMarginsTop 0.2 `
-TitleFontBold `
-TitleFontSize 16
Single Stacked Bar Chart
Use New-SingleStackedBarChart to show a single bar divided into labelled segments — useful for illustrating licence consumption or a single capacity resource.
$chartLabels = [string[]]$LicenseUsage.WorkloadType
$chartValues = [double[]]$LicenseUsage.UsedInstances
$chartFileItem = New-SingleStackedBarChart `
-Title ' ' `
-Values $chartValues `
-Label 'Workload Type' `
-LegendCategories $chartLabels `
-EnableCustomColorPalette `
-CustomColorPalette @('#DFF0D0', '#FFF3C4', '#FECDD1', '#ADACAF', '#B3E5FC', '#F8BBD0') `
-Width 600 -Height 200 `
-Format base64 `
-AreaOrientation Horizontal `
-EnableLegend `
-LegendOrientation Horizontal `
-LegendAlignment UpperCenter `
-TitleFontBold `
-TitleFontSize 16
Signal Chart
Use New-SignalChart for time-series or trend data — for example, CPU utilisation over time or throughput metrics. The -Values parameter expects an array of arrays, where each inner array represents one line.
# Wrap a single line's values in a jagged array
$chartValues = @(,[double[]]@(42, 55, 61, 49, 78, 65, 53))
$chartFileItem = New-SignalChart `
-Title 'CPU Utilisation (%)' `
-Values $chartValues `
-Format base64 `
-Width 600 -Height 400 `
-TitleFontBold `
-TitleFontSize 16
$readThroughput = [double[]]@(120, 145, 132, 160, 155)
$writeThroughput = [double[]]@(85, 92, 78, 101, 96)
$chartValues = @(,$readThroughput) + @(,$writeThroughput)
$chartFileItem = New-SignalChart `
-Title 'Storage Throughput (MB/s)' `
-Values $chartValues `
-Labels @('Read', 'Write') `
-Format base64 `
-Width 600 -Height 400 `
-EnableLegend `
-LegendOrientation Horizontal `
-LegendAlignment UpperCenter `
-TitleFontBold `
-TitleFontSize 16
Safety Guards
Chart generation can return $null if data is empty or an error occurs. Always validate the return value before calling Image, and verify that the underlying data contains non-zero values before rendering the chart.
if ($chartFileItem -and ($chartValues | Measure-Object -Sum).Sum -ne 0) {
Image -Text 'Chart alt text' -Align 'Center' -Percent 100 -Base64 $chartFileItem
}
Wrap the entire chart generation block in a try/catch when the data collection itself could fail:
try {
$chartFileItem = New-BarChart -Title 'Job Results' -Values $chartValues -Labels $chartLabels `
-Format base64 -Width 600 -Height 400
if ($chartFileItem -and ($chartValues | Measure-Object -Sum).Sum -ne 0) {
Image -Text 'Backup job result distribution' -Align 'Center' -Percent 100 -Base64 $chartFileItem
}
} catch {
Write-PScriboMessage -IsWarning "Unable to generate chart: $($_.Exception.Message)"
}
Color Palettes
AsBuiltReport.Chart supports 25 built-in colour palettes via the -ColorPalette parameter, or a custom palette via -EnableCustomColorPalette and -CustomColorPalette.
For consistency across report modules, use the following standard palette when representing status outcomes (Success / Warning / Failed / Unknown):
$statusCustomPalette = @('#DFF0D0', '#FFF3C4', '#FECDD1', '#ADACAF')
# Green = Success, Yellow = Warning, Pink = Failed, Gray = Unknown/None
To use a built-in palette instead:
New-PieChart -Title 'Distribution' -Values $chartValues -Labels $chartLabels `
-ColorPalette Category20 -Format base64 -Width 600 -Height 400
Available palettes: Amber, Category10, Category20, Aurora, Building, ColorblindFriendly, ColorblindFriendlyDark, Dark, DarkPastel, Frost, LightOcean, LightSpectrum, Microcharts, Nero, Nord, Normal, OneHalf, OneHalfDark, PastelWheel, Penumbra, PolarNight, Redness, SnowStorm, SummerSplash, Tsitsulin
Placing Charts in a Report
Charts should appear before their related data table within the same section, providing a visual summary that the table then backs with detail. Place the Image call, then a BlankLine, then the Table call.
Section -Style NOTOCHeading4 'Job Status Summary' {
if ($chartFileItem -and ($chartValues | Measure-Object -Sum).Sum -ne 0) {
Image -Text 'Backup job result distribution' -Align 'Center' -Percent 100 -Base64 $chartFileItem
}
BlankLine
$OutObj | Sort-Object -Property 'Name' | Table @TableParams
}
Complete Private Function Example
The following example shows a complete private function that collects backup job data, generates a bar chart of job results by status, and renders the chart above a summary table — the pattern used throughout the AsBuiltReport ecosystem.
function Get-AbrVbrBackupJobSummary {
<#
.SYNOPSIS
Used by As Built Report to retrieve Veeam VBR backup job summary information.
.DESCRIPTION
Documents the configuration of Veeam VBR in Word/HTML/Text formats using PScribo.
.NOTES
Version: 0.1.0
Author: Your Name
.LINK
https://github.com/AsBuiltReport/AsBuiltReport.Veeam.VBR
#>
[CmdletBinding()]
param ()
begin {
Write-PScriboMessage "Collecting backup job summary information."
}
process {
try {
$Jobs = Get-VBRJob -ErrorAction Stop
if ($Jobs) {
# Aggregate job results by status
$sampleData = [ordered]@{
'Success' = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'Success' } | Measure-Object).Count
'Warning' = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'Warning' } | Measure-Object).Count
'Failed' = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'Failed' } | Measure-Object).Count
'None' = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'None' } | Measure-Object).Count
}
$chartLabels = [string[]]$sampleData.Keys
$chartValues = [double[]]$sampleData.Values
$statusCustomPalette = @('#DFF0D0', '#FFF3C4', '#FECDD1', '#ADACAF')
$chartFileItem = New-BarChart `
-Title 'Backup Job Results' `
-Values $chartValues `
-Labels $chartLabels `
-LabelXAxis 'Status' `
-LabelYAxis 'Job Count' `
-EnableCustomColorPalette `
-CustomColorPalette $statusCustomPalette `
-Width 600 -Height 400 `
-Format base64 `
-EnableLegend `
-LegendOrientation Horizontal `
-LegendAlignment UpperCenter `
-AxesMarginsTop 0.5 `
-TitleFontBold `
-TitleFontSize 16
Section -Style Heading3 'Backup Jobs' {
Paragraph "The following section provides a summary of all backup jobs and their current status."
BlankLine
Section -Style NOTOCHeading4 'Job Status Summary' {
if ($chartFileItem -and ($chartValues | Measure-Object -Sum).Sum -ne 0) {
Image -Text 'Backup job result distribution' -Align 'Center' -Percent 100 -Base64 $chartFileItem
}
BlankLine
$OutObj = foreach ($Job in ($Jobs | Sort-Object Name)) {
try {
[PSCustomObject]@{
'Name' = $Job.Name
'Type' = $Job.JobType
'Last Result' = $Job.Info.LatestStatus
'Last Run' = $Job.Info.EndTimeUtc
}
} catch {
Write-PScriboMessage -IsWarning "$($Job.Name): $($_.Exception.Message)"
}
}
$TableParams = @{
Name = 'Backup Job Status'
List = $false
ColumnWidths = 35, 25, 20, 20
}
if ($Report.ShowTableCaptions) {
$TableParams['Caption'] = "- $($TableParams.Name)"
}
$OutObj | Table @TableParams
}
}
}
} catch {
Write-PScriboMessage -IsWarning "Backup Job Summary: $($_.Exception.Message)"
}
}
end {}
}
Localising Chart Text
When your module supports multiple languages, store chart titles and Image alt-text in your language file alongside other translated strings.
GetAbrVbrBackupJobSummary = ConvertFrom-StringData @'
Collecting = Collecting backup job summary information.
Heading = Backup Jobs
Paragraph = The following section provides a summary of all backup jobs and their current status.
StatusSection = Job Status Summary
ChartTitle = Backup Job Results
ChartAltText = Backup job result distribution
ChartXAxis = Status
ChartYAxis = Job Count
Success = Success
Warning = Warning
Failed = Failed
None = None
'@
begin {
$LocalizedData = $reportTranslate.GetAbrVbrBackupJobSummary
Write-PScriboMessage $LocalizedData.Collecting
}
process {
$sampleData = [ordered]@{
($LocalizedData.Success) = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'Success' } | Measure-Object).Count
($LocalizedData.Warning) = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'Warning' } | Measure-Object).Count
($LocalizedData.Failed) = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'Failed' } | Measure-Object).Count
($LocalizedData.None) = ($Jobs | Where-Object { $_.Info.LatestStatus -eq 'None' } | Measure-Object).Count
}
$chartLabels = [string[]]$sampleData.Keys
$chartValues = [double[]]$sampleData.Values
$chartFileItem = New-BarChart `
-Title $LocalizedData.ChartTitle `
-Values $chartValues `
-Labels $chartLabels `
-LabelXAxis $LocalizedData.ChartXAxis `
-LabelYAxis $LocalizedData.ChartYAxis `
-EnableCustomColorPalette `
-CustomColorPalette @('#DFF0D0', '#FFF3C4', '#FECDD1', '#ADACAF') `
-Width 600 -Height 400 `
-Format base64 `
-EnableLegend -LegendOrientation Horizontal -LegendAlignment UpperCenter `
-AxesMarginsTop 0.5 -TitleFontBold -TitleFontSize 16
if ($chartFileItem -and ($chartValues | Measure-Object -Sum).Sum -ne 0) {
Image -Text $LocalizedData.ChartAltText -Align 'Center' -Percent 100 -Base64 $chartFileItem
}
}
Common Parameters Reference
The following parameters are available on all five chart cmdlets:
| Parameter | Type | Default | Description |
|---|---|---|---|
-Title |
String | — | Chart title text |
-Format |
Formats | — | Output format: png, jpg, jpeg, bmp, svg, base64 |
-Width |
Int | 400 | Chart width in pixels |
-Height |
Int | 300 | Chart height in pixels |
-FontName |
String | Arial | Base font for all text elements |
-TitleFontSize |
Int | 14 | Title text size in points |
-TitleFontBold |
Switch | — | Render title in bold |
-TitleFontColor |
BasicColors | — | Title text colour |
-EnableLegend |
Switch | — | Show the chart legend |
-LegendOrientation |
Orientation | — | Horizontal or Vertical |
-LegendAlignment |
Alignments | — | 9-position alignment (e.g. UpperRight, UpperCenter) |
-ColorPalette |
ColorPalettes | — | Built-in palette name |
-EnableCustomColorPalette |
Switch | — | Use -CustomColorPalette hex values |
-CustomColorPalette |
String[] | — | Array of hex colour codes |
-EnableBorder |
Switch | — | Draw a border around the chart |
-BorderColor |
BasicColors | — | Border colour |
-BorderSize |
Int | — | Border thickness |
-EnableWatermark |
Switch | — | Overlay a watermark on the chart |
-WatermarkText |
String | Confidential | Watermark text |
-WatermarkOpacity |
Double | 0.3 | Watermark opacity (0.0–1.0) |
-OutputFolderPath |
DirectoryInfo | — | Write chart to this folder (not needed with base64) |
-Filename |
String | — | Output filename (auto-generated if omitted) |
Summary of Best Practices
- Always use
-Format base64— embedding base64 keeps the chart in memory and avoids writing files to the output folder. - Guard every
Imagecall — check$chartFileItemis not null and the values sum to a non-zero total before rendering. - Cast arrays explicitly —
[string[]]for labels,[double[]]for values. Passing untyped arrays causes parameter binding errors. - Use the standard status palette —
@('#DFF0D0', '#FFF3C4', '#FECDD1', '#ADACAF')(green, yellow, pink, grey) for consistent status visualisations across modules. - Place charts before tables — charts provide visual context; the table provides the underlying detail.
- Keep chart sections out of the TOC — use
NOTOCHeading4orNOTOCHeading5for the section containing the chart and table so individual chart sections do not clutter the Table of Contents. - Localise chart text — store chart titles, axis labels, and
Imagealt-text in your language file alongside other translatable strings.