83 lines
3.4 KiB
PowerShell
83 lines
3.4 KiB
PowerShell
|
|
function Write-PersonaSummary {
|
||
|
|
<#
|
||
|
|
.SYNOPSIS
|
||
|
|
Renders the rule-match table, outcome totals, and reconciliation result
|
||
|
|
(FR-019, FR-020, FR-021).
|
||
|
|
|
||
|
|
.DESCRIPTION
|
||
|
|
Emitted every summaryInterval users and once at completion.
|
||
|
|
|
||
|
|
Every business rule appears, including disabled rules and rules with zero
|
||
|
|
matches. A rule that never fired and a rule that is not in the configuration
|
||
|
|
look identical if zero-match rules are omitted, and the difference is exactly
|
||
|
|
what an operator investigating "why did nobody get classified as Tier0" needs
|
||
|
|
to see.
|
||
|
|
|
||
|
|
Reconciliation is displayed on every summary, not only when it fails. A check
|
||
|
|
that is only visible when broken gives an operator no reason to believe it
|
||
|
|
ran at all.
|
||
|
|
|
||
|
|
.PARAMETER Counters
|
||
|
|
The run counter set.
|
||
|
|
|
||
|
|
.PARAMETER SummaryType
|
||
|
|
Interim or Final. Final is emitted regardless of interval, including when
|
||
|
|
the interval is 0 (FR-020).
|
||
|
|
|
||
|
|
.PARAMETER Mode
|
||
|
|
Preview or Enforce, shown in the header so a screenshot of a summary is
|
||
|
|
self-describing.
|
||
|
|
#>
|
||
|
|
[CmdletBinding()]
|
||
|
|
param(
|
||
|
|
[Parameter(Mandatory)]
|
||
|
|
[object] $Counters,
|
||
|
|
|
||
|
|
[ValidateSet('Interim', 'Final')]
|
||
|
|
[string] $SummaryType = 'Interim',
|
||
|
|
|
||
|
|
[ValidateSet('Preview', 'Enforce')]
|
||
|
|
[string] $Mode = 'Preview'
|
||
|
|
)
|
||
|
|
|
||
|
|
$reconciled = Test-PersonaReconciliation -Counters $Counters
|
||
|
|
|
||
|
|
Write-Host ''
|
||
|
|
Write-Host ('=' * 100) -ForegroundColor DarkGray
|
||
|
|
Write-Host ("{0} summary - mode: {1} - processed: {2}" -f $SummaryType, $Mode, $Counters.Processed) -ForegroundColor Cyan
|
||
|
|
Write-Host ('=' * 100) -ForegroundColor DarkGray
|
||
|
|
|
||
|
|
Write-Host ('{0,-28} {1,-40} {2,-9} {3,10} {4,8}' -f 'Rule ID', 'Name', 'Priority', 'Enabled', 'Matches') -ForegroundColor DarkGray
|
||
|
|
|
||
|
|
foreach ($entry in $Counters.RuleCounts) {
|
||
|
|
# A disabled rule is dimmed rather than hidden: it is part of the
|
||
|
|
# configuration and its absence from the output would read as a deletion.
|
||
|
|
$colour = if (-not $entry.Enabled) { 'DarkGray' } elseif ($entry.Matches -gt 0) { 'Green' } else { 'Gray' }
|
||
|
|
|
||
|
|
Write-Host ('{0,-28} {1,-40} {2,-9} {3,10} {4,8}' -f
|
||
|
|
$entry.RuleId,
|
||
|
|
($entry.Name.Length -gt 40 ? $entry.Name.Substring(0, 37) + '...' : $entry.Name),
|
||
|
|
$entry.Priority,
|
||
|
|
$entry.Enabled,
|
||
|
|
$entry.Matches) -ForegroundColor $colour
|
||
|
|
}
|
||
|
|
|
||
|
|
Write-Host ''
|
||
|
|
Write-Host ('Outcomes Matched: {0} Unclassified: {1} EvaluationError: {2}' -f
|
||
|
|
$Counters.Matched, $Counters.Unclassified, $Counters.EvaluationError)
|
||
|
|
Write-Host ('Actions Unchanged: {0} WouldUpdate: {1} Updated: {2} UpdateFailed: {3} Skipped: {4}' -f
|
||
|
|
$Counters.Unchanged, $Counters.WouldUpdate, $Counters.Updated, $Counters.UpdateFailed, $Counters.Skipped)
|
||
|
|
|
||
|
|
if ($reconciled) {
|
||
|
|
Write-Host ('Reconciliation PASS {0} = {1} + {2} + {3}' -f
|
||
|
|
$Counters.Processed, $Counters.Matched, $Counters.Unclassified, $Counters.EvaluationError) -ForegroundColor Green
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
Write-Host ('Reconciliation FAIL {0} != {1} + {2} + {3} - this is an engine defect (FR-021)' -f
|
||
|
|
$Counters.Processed, $Counters.Matched, $Counters.Unclassified, $Counters.EvaluationError) -ForegroundColor Red
|
||
|
|
}
|
||
|
|
|
||
|
|
Write-Host ('=' * 100) -ForegroundColor DarkGray
|
||
|
|
Write-Host ''
|
||
|
|
}
|