Public/Test-InfraPulseReport.ps1
|
function Test-InfraPulseReport { <# .SYNOPSIS Evaluates InfraPulse reports against a release or change policy. .DESCRIPTION Applies blocking statuses, a warning budget, and optional wildcard ignore rules to one or more reports and returns an InfraPulse.PolicyEvaluation object describing the outcome. The policy can be supplied inline through FailOn and MaximumWarnings or loaded from a validated PowerShell data file. The command never exits the PowerShell host process. It throws only when ThrowOnFailure is explicitly requested and the evaluation fails. .PARAMETER InputObject One or more InfraPulse.Report objects. .PARAMETER FailOn Result statuses that block the evaluation. Defaults to Critical and Unknown. .PARAMETER MaximumWarnings Number of Warning results tolerated after ignore rules are applied. Defaults to 0. .PARAMETER PolicyPath Path to a policy data file with FailOn, MaximumWarnings, and Ignore rules. Cannot be combined with FailOn or MaximumWarnings. .PARAMETER Quiet Returns only a Boolean evaluation result. .PARAMETER ThrowOnFailure Throws a terminating error with the evaluation message when the policy is not satisfied. .EXAMPLE $evaluation = $report | Test-InfraPulseReport -FailOn Critical, Unknown -MaximumWarnings 0 .EXAMPLE $report | Test-InfraPulseReport -PolicyPath .\config\change-policy.example.psd1 -ThrowOnFailure #> [CmdletBinding(DefaultParameterSetName = 'Inline')] param( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [object]$InputObject, [Parameter(ParameterSetName = 'Inline')] [ValidateSet('Healthy', 'Warning', 'Critical', 'Unknown', 'Skipped')] [string[]]$FailOn = @('Critical', 'Unknown'), [Parameter(ParameterSetName = 'Inline')] [ValidateRange(0, 2147483647)] [int]$MaximumWarnings = 0, [Parameter(Mandatory, ParameterSetName = 'Policy')] [ValidateNotNullOrEmpty()] [string]$PolicyPath, [switch]$Quiet, [switch]$ThrowOnFailure ) begin { $reports = New-Object System.Collections.Generic.List[object] } process { if ($null -eq $InputObject.PSObject.Properties['Results'] -or $null -eq $InputObject.PSObject.Properties['OverallStatus']) { throw 'InputObject is not an InfraPulse report.' } [void]$reports.Add($InputObject) } end { if ($reports.Count -eq 0) { throw 'No InfraPulse reports were supplied.' } if ($PSCmdlet.ParameterSetName -eq 'Policy') { $policy = Import-InfraPulseChangePolicy -Path $PolicyPath $policySource = (Resolve-Path -LiteralPath $PolicyPath).ProviderPath } else { $policy = [pscustomobject]@{ FailOn = @($FailOn | Select-Object -Unique) MaximumWarnings = $MaximumWarnings Ignore = @() } $policySource = 'Inline parameters' } $allResults = @($reports | ForEach-Object { @($_.Results) }) $ignoredResults = New-Object System.Collections.Generic.List[object] $evaluatedResults = New-Object System.Collections.Generic.List[object] foreach ($result in $allResults) { if (Test-InfraPulseIgnoreRuleMatch -Result $result -Rules $policy.Ignore) { [void]$ignoredResults.Add($result) } else { [void]$evaluatedResults.Add($result) } } $blocking = @($evaluatedResults | Where-Object { [string]$_.Status -in @($policy.FailOn) }) $warningCount = @($evaluatedResults | Where-Object { [string]$_.Status -eq 'Warning' -and 'Warning' -notin @($policy.FailOn) }).Count $warningsExceeded = $warningCount -gt [int]$policy.MaximumWarnings $passed = ($blocking.Count -eq 0) -and (-not $warningsExceeded) $messageParts = @() if ($blocking.Count -gt 0) { $blockingStatuses = @($blocking | ForEach-Object { [string]$_.Status } | Select-Object -Unique | Sort-Object) -join ', ' $messageParts += "$($blocking.Count) blocking result(s) with status $blockingStatuses" } if ($warningsExceeded) { $messageParts += "$warningCount warning(s) exceed the budget of $($policy.MaximumWarnings)" } $message = if ($passed) { "$($evaluatedResults.Count) evaluated result(s) satisfy the policy; $($ignoredResults.Count) result(s) were ignored." } else { 'Policy evaluation failed: ' + ($messageParts -join ' and ') + "; $($ignoredResults.Count) result(s) were ignored." } $evaluation = [pscustomobject][ordered]@{ Passed = $passed Message = $message PolicySource = $policySource FailOn = @($policy.FailOn) MaximumWarnings = [int]$policy.MaximumWarnings TotalResults = $allResults.Count EvaluatedCount = $evaluatedResults.Count IgnoredCount = $ignoredResults.Count BlockingCount = $blocking.Count WarningCount = $warningCount Blocking = @( foreach ($result in $blocking) { [pscustomobject][ordered]@{ ComputerName = [string]$result.ComputerName CheckName = [string]$result.CheckName Target = [string]$result.Target Status = [string]$result.Status Message = [string]$result.Message } } ) ComputerNames = @($reports | ForEach-Object { [string]$_.ComputerName } | Select-Object -Unique) GeneratedAtUtc = [DateTime]::UtcNow } $evaluation.PSObject.TypeNames.Insert(0, 'InfraPulse.PolicyEvaluation') if (-not $passed -and $ThrowOnFailure) { throw $message } if ($Quiet) { return $passed } return $evaluation } } |