Private/Get-ArgusScore.ps1
|
function Get-ArgusScore { <# .SYNOPSIS Computes the Governance Score, grade and coverage, overall and per area (spec section 6). .DESCRIPTION - Weight per check = Scoring.Weights[Severity]. - Credit: Passed = 1, Investigate = Scoring.InvestigateCredit, Failed = 0. - Skipped, Error and NotRun are excluded from the denominator. - Score = round(100 * sum(weight * credit) / sum(weight of evaluated checks)), midpoint away from zero. - Coverage = evaluated weight / weight of the selected checks (all statuses except NotRun), in percent. When the selected weight is 0 (for example only Info checks) coverage is computed on check counts. - IsPartial when coverage < Scoring.PartialCoverageThreshold. - Grade: A >= 90, B >= 75, C >= 60, D >= 40, F < 40. When no weighted check was evaluated, Score and Grade are $null and the run is Partial. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $Result, [Parameter(Mandatory)] [System.Collections.IDictionary] $Scoring ) $weights = $Scoring['Weights'] $investigateCredit = [double]$Scoring['InvestigateCredit'] $threshold = [double]$Scoring['PartialCoverageThreshold'] $measure = { param([object[]] $Items) $counts = [ordered]@{ Total = $Items.Count } foreach ($status in $script:ArgusStatuses) { $counts[$status] = @($Items | Where-Object { $_.Status -eq $status }).Count } $earned = 0.0 $evaluatedWeight = 0.0 $selectedWeight = 0.0 foreach ($item in $Items) { if ($item.Status -eq 'NotRun') { continue } $weight = [double]$weights[$item.Severity] $selectedWeight += $weight switch ($item.Status) { 'Passed' { $evaluatedWeight += $weight; $earned += $weight } 'Investigate' { $evaluatedWeight += $weight; $earned += $weight * $investigateCredit } 'Failed' { $evaluatedWeight += $weight } } } $selectedCount = $counts.Total - $counts.NotRun $evaluatedCount = $counts.Passed + $counts.Failed + $counts.Investigate $coverage = if ($selectedWeight -gt 0) { 100 * $evaluatedWeight / $selectedWeight } elseif ($selectedCount -gt 0) { 100 * $evaluatedCount / $selectedCount } else { 0 } $coverage = [math]::Round($coverage, 1, [System.MidpointRounding]::AwayFromZero) $score = if ($evaluatedWeight -gt 0) { [int][math]::Round(100 * $earned / $evaluatedWeight, [System.MidpointRounding]::AwayFromZero) } else { $null } $grade = if ($null -eq $score) { $null } elseif ($score -ge 90) { 'A' } elseif ($score -ge 75) { 'B' } elseif ($score -ge 60) { 'C' } elseif ($score -ge 40) { 'D' } else { 'F' } [ordered]@{ Score = $score Grade = $grade Coverage = $coverage IsPartial = ($null -eq $score) -or ($coverage -lt $threshold) EarnedWeight = $earned EvaluatedWeight = $evaluatedWeight SelectedWeight = $selectedWeight Counts = [pscustomobject]$counts } } $items = @($Result) $overall = & $measure $items $areas = foreach ($area in $script:ArgusAreas.Keys) { $areaItems = @($items | Where-Object { $_.Area -eq $area }) if ($areaItems.Count -eq 0) { continue } $areaScore = [ordered]@{ Area = $area; DisplayName = $script:ArgusAreas[$area].DisplayName } $measured = & $measure $areaItems foreach ($key in $measured.Keys) { $areaScore[$key] = $measured[$key] } [pscustomobject]$areaScore } $overall['Areas'] = @($areas) $overall['Weights'] = $weights $overall['InvestigateCredit'] = $investigateCredit $overall['PartialCoverageThreshold'] = $threshold [pscustomobject]$overall } |