Public/Test-SqlSpnPlan.ps1
|
# ============================================================================= # Script : Test-SqlSpnPlan.ps1 # Author : Keith Ramsey # ============================================================================= # Change Log # ----------------------------------------------------------------------------- # 2026-05-09 Keith Ramsey Phase 2 release polish - DR-202 standard header applied. # 2026-05-13 Keith Ramsey Fix operator-precedence bug at the missing-fields check; # '-not $expr -contains $x' parses as '($false) -contains $x' # so the Invalid branch was dead code. Replace with -notcontains. # ============================================================================= function Test-SqlSpnPlan { <# .SYNOPSIS Validates a plan object's shape before execution. .DESCRIPTION Confirms the plan carries the expected fields (AccountDn, ProposedSpns, Role) and that ProposedSpns is non-empty. Forest-wide duplicate detection runs inside Invoke-SqlSpnExecutionEngine (setspn -Q with optional -T) where it can surface conflicts as structured warnings; this command is the cheap local-shape check that runs before the expensive AD round-trip. .PARAMETER SpnPlan A plan object produced by New-SqlSpnPlan. .EXAMPLE $plan | Test-SqlSpnPlan .EXAMPLE $result = Test-SqlSpnPlan -SpnPlan $plan if ($result.Status -ne 'Clear') { throw "Plan invalid: $($result.Reason)" } .OUTPUTS PSCustomObject with Status (Clear / Invalid / Empty), Reason (when not Clear), and Spns (when Clear). .NOTES Status meanings: Clear - shape is valid and plan is non-empty; safe to pass to engine. Invalid - missing one or more required fields; plan was not built correctly. Empty - plan has zero proposed SPNs; nothing to register. #> [CmdletBinding()] param([Parameter(Mandatory=$true, ValueFromPipeline=$true)]$SpnPlan) process { $missing = @() foreach ($field in 'AccountDn', 'ProposedSpns', 'Role') { if ($SpnPlan.PSObject.Properties.Name -notcontains $field) { $missing += $field } } if ($missing.Count -gt 0) { return [PSCustomObject]@{ Status = 'Invalid'; Reason = "Missing fields: $($missing -join ', ')" } } if (-not $SpnPlan.ProposedSpns -or $SpnPlan.ProposedSpns.Count -eq 0) { return [PSCustomObject]@{ Status = 'Empty'; Reason = 'No SPNs proposed' } } return [PSCustomObject]@{ Status = 'Clear'; Spns = $SpnPlan.ProposedSpns } } } |