Public/Start-SqlSpnManager.ps1
|
# ============================================================================= # Script : Start-SqlSpnManager.ps1 # Author : Keith Ramsey # ============================================================================= # Change Log # ----------------------------------------------------------------------------- # 2026-05-09 Keith Ramsey Phase 2 release polish - DR-202 standard header applied. # 2026-05-21 Keith Ramsey DR-309 v1 surface narrowing: scenarioName array no # longer includes MSDTC (matches the picker change in # Get-SqlSpnScenarioChoice). # ============================================================================= function Start-SqlSpnManager { <# .SYNOPSIS Interactive entry point: walks the operator through SPN registration end-to-end. .DESCRIPTION Composes the full pipeline: Get-SqlSpnAccount -> Get-SqlSpnInfrastructure -> New-SqlSpnPlan -> Test-SqlSpnPlan -> Invoke-SqlSpnExecutionEngine Selection of source (discovered local services vs. standard pool), target, and scenario is collected via prompts. The engine itself never prompts; only this wrapper does. Pester unit tests target the underlying functions directly without going through this wrapper. .PARAMETER AutoConfirm Skip the final Y/N execution prompt. Other prompts still run unless mocked. .EXAMPLE Start-SqlSpnManager .EXAMPLE Start-SqlSpnManager -AutoConfirm .OUTPUTS None. Side effects: SPN registrations and audit log entries. .NOTES Per DR-007 the public engine surface (New-SqlSpnPlan, Invoke-SqlSpnExecutionEngine) is fully parameterizable. Use those directly for unattended automation. #> [CmdletBinding(SupportsShouldProcess)] param([switch]$AutoConfirm) # Standard Pool resolver: hardcoded 10-name default per DR-106; optional # JSON override via $env:SQLSPN_STANDARD_POOL per DR-205. $standardPool = Resolve-SqlSpnStandardPool $sourceSelection = Get-SqlSpnSourceChoice if ($sourceSelection -eq 0) { $candidates = Get-SqlSpnDiscoveryEngine $selected = Get-SqlSpnVisualAccountSelection -AccountList $candidates if ($null -eq $selected) { return } $samAccountName = $selected.AccountName $manualPort = $selected.Port } else { $standardList = $standardPool.GetEnumerator() | Select-Object @{N='Role'; E={$_.Name}}, @{N='AccountName'; E={$_.Value}} $selected = Get-SqlSpnVisualAccountSelection -AccountList $standardList if ($null -eq $selected) { return } $samAccountName = $selected.AccountName $manualPort = $null } $scenarioIndex = Get-SqlSpnScenarioChoice $scenarioName = @('Standalone','FCI','AlwaysOn')[$scenarioIndex] $targetName = Get-SqlSpnTargetName # DR-103: redirect virtual / built-in identities to the local computer object # before AD verification. FCI Engine has its own redirect (Resolve-SqlSpnFciCno) # inside New-SqlSpnPlan. $samAccountName = Resolve-SqlSpnVirtualAccount -AccountName $samAccountName $account = Get-SqlSpnAccount -SamAccountName $samAccountName if (-not $account) { return } $infraParams = @{ Scenario = $scenarioName; TargetName = $targetName } if ($manualPort) { $infraParams.ManualPort = $manualPort } $infra = Get-SqlSpnInfrastructure @infraParams $plan = New-SqlSpnPlan -VerifiedAccount $account -Infrastructure $infra -Role Engine if (-not $plan) { return } $validation = Test-SqlSpnPlan -SpnPlan $plan if ($validation.Status -ne 'Clear') { Write-Warning "Plan validation: $($validation.Status) - $($validation.Reason)" return } Write-Host "`nPROPOSED SPNs:" -ForegroundColor Yellow $plan.ProposedSpns | ForEach-Object { Write-Host " $_" } Write-Host "ACCOUNT: $($plan.AccountDn)" if ($plan.CrossForest) { Write-Host "CROSS-FOREST: -T $($plan.TargetDomain)" -ForegroundColor Cyan } $proceed = if ($AutoConfirm) { $true } else { Get-SqlSpnExecutionConfirmation } if ($proceed -and $PSCmdlet.ShouldProcess("$($plan.ProposedSpns.Count) SPN(s) on $($plan.AccountDn)", 'Register SPNs')) { $plan | Invoke-SqlSpnExecutionEngine } } |