Public/Export-RaidinessReport.ps1
|
# psrunner-lint allow: New-Item — creates the local output directory for the report; never a tenant object function Export-RaidinessReport { <# .SYNOPSIS Fills the bundled single-file HTML report with the collected data and opens it in your browser. .DESCRIPTION The report template (assets/ReportTemplate.html) carries the whole assessment engine — the checks, the scorecard, the roadmap and the licence advisor — compiled into one self-contained page. This cmdlet only injects the collected files into the page's data slot and writes the result; every calculation happens in your browser when the page opens. No network, no upload, nothing leaves the machine. -Markdown and -LLM ask the page for extra downloads next to the HTML report: a markdown version (report.md) and an LLM-ready bundle (llm-bundle.zip) you can hand to a model of your choice, with your own key, at your own cost — Raidiness itself never calls a model. Both hash user names and e-mail addresses; -IncludeIdentities keeps them as they are. The HTML report itself always shows real identities and stays on your machine. .PARAMETER InputPath Directory with the collected data. Default: ./raidiness-data .PARAMETER OutputPath The report file to write. Default: ./raidiness-report.html .PARAMETER Customer Organisation name shown on the report. .PARAMETER NoOpen Write the file without opening the browser. .PARAMETER Markdown Offer a markdown version of the report (report.md) as a download in the page. .PARAMETER LLM Offer an LLM-ready bundle (llm-bundle.zip: markdown report, findings and measurements) as a download in the page, for use with your own model and key. Identities are hashed unless -IncludeIdentities. .PARAMETER IncludeIdentities Keep real user names and e-mail addresses in the markdown/LLM files instead of hashing them. Only meaningful with -Markdown or -LLM. .EXAMPLE Export-RaidinessReport -Customer 'Contoso Ltd' .EXAMPLE Export-RaidinessReport -Markdown -LLM #> [CmdletBinding(DefaultParameterSetName = 'Legacy')] param( # A run folder from Invoke-Raidiness -Path: the evidence is read from # its data/ subfolder and every artifact is written back into it. [Parameter(ParameterSetName = 'RunFolder', Mandatory = $true)] [string] $RunPath, [Parameter(ParameterSetName = 'Legacy')] [string] $InputPath = './raidiness-data', [Parameter(ParameterSetName = 'Legacy')] [string] $OutputPath = './raidiness-report.html', [string] $Customer = 'Your organisation', [switch] $NoOpen, [switch] $Markdown, [switch] $LLM, [switch] $IncludeIdentities, # Also print the report to PDF (run folder only; needs the browser). [switch] $Pdf, # Do not drive a browser: write the report and open it, as before. [switch] $NoBrowser, [string] $BrowserPath, [int] $TimeoutSeconds = 180 ) $ErrorActionPreference = 'Stop' $runFolder = $PSCmdlet.ParameterSetName -eq 'RunFolder' if ($runFolder) { if (-not (Test-Path -Path $RunPath)) { throw "No run folder at $RunPath." } $RunPath = (Resolve-Path -Path $RunPath).Path $InputPath = Join-Path $RunPath 'data' $OutputPath = Join-Path $RunPath 'report.html' if (-not (Get-RaidinessLogPath)) { Open-RaidinessLog -Path $RunPath | Out-Null } } $template = Join-Path $PSScriptRoot '..' 'assets' 'ReportTemplate.html' if (-not (Test-Path $template)) { throw "Report template not found at $template. In a source checkout, build it first: bun run template:build" } if (-not (Test-Path $InputPath)) { throw "No collected data at $InputPath. Run Connect-Raidiness and Invoke-Raidiness first." } $files = @(Get-ChildItem -Path $InputPath -File | Where-Object { $_.Extension -in '.json', '.csv' }) if ($files.Count -eq 0) { throw "No .json or .csv files found in $InputPath." } if ($LLM) { Write-Host 'Note: any costs incurred with your LLM provider are your own; Raidiness does not call any model.' -ForegroundColor Cyan Write-Host 'User names and e-mail addresses are hashed in the bundle unless -IncludeIdentities is given.' -ForegroundColor Cyan } if ($IncludeIdentities) { if ($LLM -or $Markdown) { Write-Warning '-IncludeIdentities: real user identities will be included in files meant for an external model. Share them only where that is acceptable.' } else { Write-Warning '-IncludeIdentities has no effect without -Markdown or -LLM.' } } $payload = [ordered]@{ raidinessCollection = [ordered]@{ version = '1.0' customer = $Customer generatedAt = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ') exports = [ordered]@{ markdown = [bool] $Markdown llm = [bool] $LLM includeIdentities = [bool] $IncludeIdentities } } files = @( foreach ($file in $files) { [ordered]@{ name = $file.Name text = Get-Content -Path $file.FullName -Raw } } ) } # `</` must not terminate the surrounding <script> block early. $json = (ConvertTo-Json -InputObject $payload -Depth 8 -Compress).Replace('</', '<\/') $html = Get-Content -Path $template -Raw $pattern = '(?s)(<script id="raidiness-data" type="application/json">).*?(</script>)' if ($html -notmatch $pattern) { throw 'The report template has no data slot — it looks like a broken build.' } $filled = [regex]::Replace($html, $pattern, { param($m) $m.Groups[1].Value + $json + $m.Groups[2].Value }) # -OutputPath used to be written without its directory existing. $parent = Split-Path -Path $OutputPath -Parent if ($parent -and -not (Test-Path -Path $parent)) { New-Item -ItemType Directory -Path $parent -Force | Out-Null } $filled | Out-File -FilePath $OutputPath -Encoding utf8 $resolved = (Resolve-Path $OutputPath).Path Write-Host "Report written to $resolved ($($files.Count) input file(s))." -ForegroundColor Green # A run folder finishes itself: the same page, run headlessly, writes # run.json, report.md, the LLM bundle and the PDF next to the report # instead of asking someone to click four download buttons. $bridged = $false if ($runFolder -and -not $NoBrowser) { $browser = Get-RaidinessBrowser -BrowserPath $BrowserPath if ($browser) { $exported = Export-RaidinessArtifact -ReportPath $resolved -RunPath $RunPath -Browser $browser -Pdf:$Pdf -TimeoutSeconds $TimeoutSeconds if ($exported.Ok) { $bridged = $true Write-Host "Wrote $($exported.Files -join ', ') into $RunPath" -ForegroundColor Green } else { Write-Warning "The exports could not be built: $($exported.Reason)" Write-Host 'Open the report and use its download buttons instead.' -ForegroundColor Yellow } } else { Write-Warning 'No Chromium-based browser found, so only report.html was written. Install Microsoft Edge, or open the report and use its download buttons.' } Write-Host 'DOCX, XLSX and PPTX are produced by the Node CLI only (bun cli/src/index.ts --exports docx,xlsx).' -ForegroundColor DarkGray } if ((-not $bridged) -and ($Markdown -or $LLM)) { $offers = @(($Markdown ? 'report.md' : $null), ($LLM ? 'llm-bundle.zip' : $null) | Where-Object { $_ }) Write-Host "The page offers $($offers -join ' and ') as download(s)." -ForegroundColor Green } if ($runFolder) { Close-RaidinessLog | Out-Null } # A run folder that already has its files does not need a browser window. if ((-not $NoOpen) -and (-not $bridged)) { # psrunner-lint allow: Start-Process — opens the generated local report in the default browser; never touches the tenant Start-Process $resolved } } |