Public/Start-SqlSpnConfiguration.ps1
|
# ============================================================================= # Script : Start-SqlSpnConfiguration.ps1 # Author : Keith Ramsey # ============================================================================= # Change Log # ----------------------------------------------------------------------------- # 2026-05-09 Keith Ramsey Phase 2 release polish - DR-202 standard header applied. # 2026-05-17 Keith Ramsey DR-308: pass-through -PassThru. When set, returns the # engine's SqlSpn.ExecutionResult to the caller. # Additive; default behaviour unchanged. # 2026-05-21 Keith Ramsey DR-309 v1 surface narrowing: -Scenario reduced to # Standalone,AlwaysOn,FCI (no MSDTC); -Role reduced # to Engine,Agent (no SSAS,SSRS,Browser). Help text # updated to match the v1.4.0 surface. # ============================================================================= function Start-SqlSpnConfiguration { <# .SYNOPSIS Programmatic, parameterized entry point for SPN registration with policy compliance. .DESCRIPTION The non-interactive counterpart to Start-SqlSpnManager. Composes the full registration pipeline from named parameters so it can be called from scripts, automation, or scheduled tasks: Resolve-SqlPolicyFromContext -> Assert-SqlAccountStandard -> Get-SqlSpnInfrastructure -> Get-SqlSpnAccount -> New-SqlSpnPlan -> Test-SqlSpnPlan -> Invoke-SqlSpnExecutionEngine The policy-compliance step (Assert-SqlAccountStandard) is the differentiator from a hand-rolled pipeline: it validates that the account follows the configured naming/OU/object-class convention before any SPN work begins. Honors ShouldProcess via the underlying engine. Use -WhatIf to preview, or -Force (which sets -Confirm:$false on Invoke-SqlSpnExecutionEngine) to skip all prompts. .PARAMETER SamAccountName SAM account name to register the SPN against (e.g., svc_sql_prod or SQLFCI01$). .PARAMETER Scenario Infrastructure type: Standalone, AlwaysOn, or FCI. (MSDTC deferred per DR-309.) .PARAMETER Role SQL service role: Engine or Agent. (SSAS, SSRS, Browser deferred per DR-309.) .PARAMETER TargetName DNS name of the server, virtual computer, or AG listener. .PARAMETER ManualPort Override automatic port discovery. .PARAMETER InstanceName SQL instance name. Defaults to MSSQLSERVER (default instance). .PARAMETER VirtualComputerAccount Optional explicit VCO override for FCI Engine registrations. .PARAMETER UseGmsa Indicates the account is a group Managed Service Account (selects the gMSA policy variant). .PARAMETER SkipCompliance Bypass the Assert-SqlAccountStandard policy check. Use when the policy table doesn't yet cover the role/scenario combination. .PARAMETER Force Skip ShouldProcess confirmation prompts during execution. .PARAMETER PassThru Opt-in. Return the engine's structured SqlSpn.ExecutionResult to the caller (see Invoke-SqlSpnExecutionEngine for the shape, locked by DR-308). Off by default so existing scripted callers see no behaviour change. The console output and audit log are written exactly as before. .EXAMPLE Start-SqlSpnConfiguration -SamAccountName svc_sql_prod -Scenario Standalone -Role Engine -TargetName SQLSRV01 .EXAMPLE Start-SqlSpnConfiguration -SamAccountName SQLFCI01$ -Scenario FCI -Role Engine -TargetName SQLFCI01 -Force .EXAMPLE $r = Start-SqlSpnConfiguration -SamAccountName svc_sql_prod -Scenario Standalone -Role Engine -TargetName SQLSRV01 -Force -PassThru if ($r.OverallStatus -eq 'PartialFailure') { $r.Spns | Where-Object Action -eq 'Failed' } .OUTPUTS Without -PassThru: none. Side effects: SPN registrations and audit log entries. With -PassThru: one SqlSpn.ExecutionResult object (see Invoke-SqlSpnExecutionEngine), in addition to the unchanged side effects. .NOTES For interactive operator use, see Start-SqlSpnManager. #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory=$true)][string]$SamAccountName, [Parameter(Mandatory=$true)][ValidateSet('Standalone','AlwaysOn','FCI')][string]$Scenario, [Parameter(Mandatory=$true)][ValidateSet('Engine','Agent')][string]$Role, [Parameter(Mandatory=$true)][string]$TargetName, [int]$ManualPort, [string]$InstanceName = 'MSSQLSERVER', [PSCustomObject]$VirtualComputerAccount, [switch]$UseGmsa, [switch]$SkipCompliance, [switch]$SkipPreflight, [switch]$Force, [switch]$PassThru ) # DR-103: redirect virtual / built-in identities to the local computer object # before compliance check + AD verification. FCI Engine has its own redirect # (Resolve-SqlSpnFciCno) inside New-SqlSpnPlan. $SamAccountName = Resolve-SqlSpnVirtualAccount -AccountName $SamAccountName if (-not $SkipCompliance) { $policyName = Resolve-SqlPolicyFromContext -Scenario $Scenario -Role $Role -UseGmsa:$UseGmsa Assert-SqlAccountStandard -SamAccountName $SamAccountName -PolicyName $policyName } $infraParams = @{ Scenario = $Scenario; TargetName = $TargetName; InstanceName = $InstanceName } if ($PSBoundParameters.ContainsKey('ManualPort')) { $infraParams.ManualPort = $ManualPort } $infra = Get-SqlSpnInfrastructure @infraParams $account = Get-SqlSpnAccount -SamAccountName $SamAccountName if (-not $account) { return } $planParams = @{ VerifiedAccount = $account; Infrastructure = $infra; Role = $Role } if ($VirtualComputerAccount) { $planParams.VirtualComputerAccount = $VirtualComputerAccount } $plan = New-SqlSpnPlan @planParams if (-not $plan) { return } $validation = $plan | Test-SqlSpnPlan if ($validation.Status -ne 'Clear') { throw "Plan validation failed: $($validation.Status) - $($validation.Reason)" } if ($PassThru) { # Opt-in programmatic path (DR-308). The engine does its own per-SPN # ShouldProcess (so -WhatIf still yields SkippedWhatIf and -Confirm # still prompts per SPN); we hand its structured result straight back # to the caller. The wrapper's aggregate ShouldProcess line is skipped # only here so a machine consumer gets the result object, not a prompt. # The default path below is byte-identical to prior behaviour. return ($plan | Invoke-SqlSpnExecutionEngine -Confirm:(-not $Force) -SkipPreflight:$SkipPreflight -PassThru) } if ($PSCmdlet.ShouldProcess("$($plan.ProposedSpns.Count) SPN(s) on $($plan.AccountDn)", 'Register SPNs')) { $plan | Invoke-SqlSpnExecutionEngine -Confirm:(-not $Force) -SkipPreflight:$SkipPreflight } } |