Private/New-HygieneFinding.ps1
|
<# .SYNOPSIS Builds one finding. Every check emits these and nothing else. .DESCRIPTION A finding is the module's unit of output: one problem, about one object, with a severity, the evidence behind it, and what to do about it. Keeping the shape fixed is what lets the HTML renderer, the CSV export and the summary counters stay simple and stay honest -- they never have to guess what a check meant. Evidence is a hashtable of the raw values the judgement was made from, so a reader can disagree with the module without re-running the audit. #> function New-HygieneFinding { [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] [string] $CheckId, [Parameter(Mandatory)] [string] $CheckName, [Parameter(Mandatory)] [string] $Category, [Parameter(Mandatory)] [ValidateSet('Critical', 'High', 'Medium', 'Low', 'Informational')] [string] $Severity, [Parameter(Mandatory)] [string] $Title, [string] $ObjectType = 'Unknown', [string] $ObjectId, [string] $ObjectName, [string] $Detail, [string] $Recommendation, [string] $Reference, [hashtable] $Evidence = @{} ) [pscustomobject]@{ PSTypeName = 'M365TenantHygiene.Finding' CheckId = $CheckId CheckName = $CheckName Category = $Category Severity = $Severity SeverityRank = (Get-HygieneSeverityRank -Severity $Severity) Title = $Title ObjectType = $ObjectType ObjectId = $ObjectId ObjectName = $ObjectName Detail = $Detail Recommendation = $Recommendation Reference = $Reference Evidence = $Evidence DetectedAt = [datetime]::UtcNow } } <# .SYNOPSIS Maps a severity name to a sort key, so Critical sorts above High everywhere. #> function Get-HygieneSeverityRank { [CmdletBinding()] [OutputType([int])] param([Parameter(Mandatory)][string] $Severity) switch ($Severity) { 'Critical' { 0 } 'High' { 1 } 'Medium' { 2 } 'Low' { 3 } 'Informational' { 4 } default { 5 } } } |