Common/Get-ReportTemplate.ps1
|
function Get-ReportTemplate { <# .SYNOPSIS Produces a self-contained HTML report document from REPORT_DATA JSON. .DESCRIPTION Inlines the React 18 production build, compiled report-app.js, CSS theme files, and window.REPORT_DATA JSON into a single HTML file with no external dependencies. The file is fully offline-capable and can be opened without a web server. .PARAMETER ReportDataJson The full window.REPORT_DATA = {...}; assignment string produced by Build-ReportDataJson. .PARAMETER ReportTitle Text for the HTML <title> element. Defaults to 'M365 Security Assessment'. .EXAMPLE $json = Build-ReportDataJson -AllFindings $findings -SectionData $sectionData -RegistryData $registry $html = Get-ReportTemplate -ReportDataJson $json -ReportTitle 'Contoso Assessment' Set-Content -Path .\report.html -Value $html -Encoding UTF8 #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [string]$ReportDataJson, [Parameter()] [string]$ReportTitle = 'M365 Security Assessment' ) $assetsDir = Join-Path -Path $PSScriptRoot -ChildPath '../assets' $themesCss = (Get-Content -Path (Join-Path $assetsDir 'report-themes.css') -Raw -ErrorAction Stop) -replace '</style>', '<\/style>' $shellCss = (Get-Content -Path (Join-Path $assetsDir 'report-shell.css') -Raw -ErrorAction Stop) -replace '</style>', '<\/style>' $reactJs = (Get-Content -Path (Join-Path $assetsDir 'react.production.min.js') -Raw -ErrorAction Stop) -replace '</script>', '<\/script>' $reactDomJs = (Get-Content -Path (Join-Path $assetsDir 'react-dom.production.min.js') -Raw -ErrorAction Stop) -replace '</script>', '<\/script>' $appJs = (Get-Content -Path (Join-Path $assetsDir 'report-app.js') -Raw -ErrorAction Stop) -replace '</script>', '<\/script>' # Use StringBuilder so JS/CSS content is appended as .NET strings — never PS-interpolated $sb = [System.Text.StringBuilder]::new(2097152) # 2 MB initial capacity $null = $sb.AppendLine('<!DOCTYPE html>') $null = $sb.AppendLine('<html data-theme="dark" data-mode="comfort">') $null = $sb.AppendLine('<head>') $null = $sb.AppendLine('<meta charset="UTF-8">') $null = $sb.AppendLine('<meta name="viewport" content="width=device-width,initial-scale=1.0">') $null = $sb.AppendLine("<title>$([System.Web.HttpUtility]::HtmlEncode($ReportTitle))</title>") $null = $sb.AppendLine('<style>') $null = $sb.Append($themesCss) $null = $sb.AppendLine() $null = $sb.Append($shellCss) $null = $sb.AppendLine() $null = $sb.AppendLine('</style>') $null = $sb.AppendLine('</head>') $null = $sb.AppendLine('<body>') $null = $sb.AppendLine('<div id="root"></div>') $null = $sb.AppendLine('<script>') $null = $sb.Append($ReportDataJson) $null = $sb.AppendLine() $null = $sb.AppendLine('</script>') $null = $sb.AppendLine('<script>') $null = $sb.Append($reactJs) $null = $sb.AppendLine() $null = $sb.AppendLine('</script>') $null = $sb.AppendLine('<script>') $null = $sb.Append($reactDomJs) $null = $sb.AppendLine() $null = $sb.AppendLine('</script>') $null = $sb.AppendLine('<script>') $null = $sb.Append($appJs) $null = $sb.AppendLine() $null = $sb.AppendLine('</script>') $null = $sb.AppendLine('</body>') $null = $sb.Append('</html>') return $sb.ToString() } |