Private/Invoke-SqlSpnSetspnAction.ps1
|
# ============================================================================= # Script : Invoke-SqlSpnSetspnAction.ps1 # Author : Keith Ramsey # ============================================================================= # Change Log # ----------------------------------------------------------------------------- # 2026-05-15 Keith Ramsey New: single home for the setspn write + truthful # success verdict that was triplicated across # Invoke-SqlSpnExecutionEngine, Add-SqlSpn, and # Remove-SqlSpn (one copy had already diverged). One # place for the verdict means a future DR-307 # resolution changes exactly one function. # ============================================================================= function Invoke-SqlSpnSetspnAction { <# .SYNOPSIS Runs one setspn write (-S / -D) and returns a truthful success verdict. .DESCRIPTION Wraps Invoke-SqlSpnNativeCall and decides success from the native exit code OR a set of failure signatures in the output. setspn.exe is an unreliable exit-code citizen across Windows builds (DR-303), so the signature check is a deliberate second signal, biased toward declaring failure when uncertain � a false success is the worst outcome for an SPN tool. Never throws: a missing setspn.exe (command-not-found) is returned as a structured failure, not an unhandled terminating error. NOTE (DR-307, OPEN): the failure signatures are English and setspn's exit code is not fully reliable, so on a non-English Windows a real failure could still be misread. The locale-independent fix (post-write AD verification) is a pending decision; when it lands it changes only this function. .PARAMETER ArgumentList setspn argument tokens, one element per argv token (e.g. @('-S','MSSQLSvc/host:1433','SAM$') or @('-T','dom','-D',$spn,$sam)). .PARAMETER IgnoreDuplicate Treat a 'Duplicate SPN' message as NOT a failure. Used by Remove-SqlSpn: removing one of a duplicate pair is success, not failure. Add-SqlSpn and the engine omit this so a duplicate-on-register is a real failure. .OUTPUTS PSCustomObject { Failed = [bool]; Output = [string] } #> [CmdletBinding()] param( [Parameter(Mandatory=$true)][string[]]$ArgumentList, [switch]$IgnoreDuplicate ) $signatures = @( 'Unable to locate account' 'FindDomainForAccount' '0x[0-9A-Fa-f]{8}' '\bfailed\b' ) if (-not $IgnoreDuplicate) { $signatures += 'Duplicate SPN' } $pattern = $signatures -join '|' $global:LASTEXITCODE = 0 try { $out = & Invoke-SqlSpnNativeCall $ArgumentList 2>&1 } catch { return [PSCustomObject]@{ Failed = $true; Output = "setspn could not be invoked: $($_.Exception.Message)" } } $text = ($out | Out-String).Trim() $failed = ($LASTEXITCODE -ne 0) -or ($text -match $pattern) return [PSCustomObject]@{ Failed = $failed; Output = $text } } |