Public/Add-SqlSpn.ps1
|
# ============================================================================= # Script : Add-SqlSpn.ps1 # Author : Keith Ramsey # ============================================================================= # Change Log # ----------------------------------------------------------------------------- # 2026-05-09 Keith Ramsey Phase 2 release polish - DR-202 standard header applied. # 2026-05-14 Keith Ramsey Array args to the native wrapper; register against # AccountName (setspn cannot resolve a DN); log # SUCCESS only when setspn actually succeeded. # 2026-05-15 Keith Ramsey Success verdict delegated to Private\ # Invoke-SqlSpnSetspnAction (shared, no drift). # ============================================================================= function Add-SqlSpn { <# .SYNOPSIS Registers each SPN from a plan against the plan's AccountDn (primitive, no conflict check). .DESCRIPTION Iterates the plan's ProposedSpns and calls setspn -S for each one, then writes a SUCCESS entry to the audit log. This is the low-level primitive: it does NOT run a forest-wide duplicate check, and it does NOT honor the cross-forest -T flag. For the full safety-checked pipeline, use Invoke-SqlSpnExecutionEngine. Honors ShouldProcess, so -WhatIf and -Confirm work. .PARAMETER SpnPlan Plan object from New-SqlSpnPlan. Required fields: AccountName, ProposedSpns. .EXAMPLE $plan = New-SqlSpnPlan -VerifiedAccount $acct -Infrastructure $infra -Role Engine $plan | Add-SqlSpn -WhatIf .EXAMPLE New-SqlSpnPlan -VerifiedAccount $acct -Infrastructure $infra -Role Engine | Add-SqlSpn .OUTPUTS None. Side effects: setspn -S calls and audit log entries. .NOTES Use Invoke-SqlSpnExecutionEngine when you need pre-flight conflict detection (setspn -Q across the forest) or cross-forest support (-T flag). #> [CmdletBinding(SupportsShouldProcess)] param([Parameter(Mandatory=$true, ValueFromPipeline=$true)][PSCustomObject]$SpnPlan) process { foreach ($Spn in $SpnPlan.ProposedSpns) { if ($PSCmdlet.ShouldProcess("Registering $Spn on $($SpnPlan.AccountName)")) { $r = Invoke-SqlSpnSetspnAction -ArgumentList @('-S', $Spn, $SpnPlan.AccountName) if ($r.Failed) { Write-Error "FAILED to register $Spn on $($SpnPlan.AccountName). setspn: $($r.Output)" Write-SqlSpnLog -Message "FAILED to register $Spn on $($SpnPlan.AccountName). setspn: $($r.Output)" -Level ERROR } else { Write-SqlSpnLog -Message "Registered $Spn on $($SpnPlan.AccountName)" -Level SUCCESS } } } } } |