Public/Get-SqlSpnInfrastructure.ps1
|
# ============================================================================= # Script : Get-SqlSpnInfrastructure.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: -Scenario reduced to # Standalone,AlwaysOn,FCI (no MSDTC). # ============================================================================= function Get-SqlSpnInfrastructure { <# .SYNOPSIS Resolves SPN-relevant infrastructure facts for a target SQL host or virtual name. .DESCRIPTION Builds the Infrastructure object that New-SqlSpnPlan consumes. Resolves FQDN from shortname using the local domain, sniffs the actual TCP port via Get-SqlActualPort (registry), detects cross-forest registration by comparing the target's DNS suffix to the local USERDNSDOMAIN, and propagates the scenario tag (Standalone / AlwaysOn / FCI) through to the plan builder. .PARAMETER Scenario The infrastructure type: Standalone, AlwaysOn, or FCI. (MSDTC deferred per DR-309.) .PARAMETER TargetName The DNS name (or shortname) of the server, virtual computer, or listener. .PARAMETER ManualPort Override the automatic port discovery. .PARAMETER InstanceName SQL instance name. Defaults to MSSQLSERVER (default instance). .EXAMPLE Get-SqlSpnInfrastructure -Scenario Standalone -TargetName SQLSRV01 .EXAMPLE Get-SqlSpnInfrastructure -Scenario FCI -TargetName SQLFCI01.contoso.com -ManualPort 55001 .OUTPUTS PSCustomObject with NetBIOS, FQDN, Port, Scenario, InstanceName, TargetDomain, CrossForest. .NOTES Cross-forest detection compares the target's DNS suffix to $env:USERDNSDOMAIN. On a workgroup or non-domain-joined host the cross-forest flag is conservative (false) and downstream callers may need to manually set the -T flag via Invoke-SqlSpnNativeCall. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)][ValidateSet('Standalone', 'AlwaysOn', 'FCI')][string]$Scenario, [Parameter(Mandatory=$true)][string]$TargetName, [int]$ManualPort, [string]$InstanceName = 'MSSQLSERVER' ) $LocalDomain = $env:USERDNSDOMAIN $TargetParts = $TargetName -split '\.', 2 $NetBIOS = $TargetParts[0] $TargetDomain = if ($TargetParts.Count -gt 1) { $TargetParts[1] } else { $LocalDomain } $FQDN = if ($TargetParts.Count -gt 1) { $TargetName } elseif ($LocalDomain) { "$NetBIOS.$LocalDomain" } else { $NetBIOS } $FinalPort = if ($PSBoundParameters.ContainsKey('ManualPort')) { $ManualPort } else { Get-SqlActualPort -ComputerName $TargetName -InstanceName $InstanceName } $CrossForest = if ($LocalDomain -and $TargetDomain -and ($LocalDomain -ne $TargetDomain)) { $true } else { $false } return [PSCustomObject]@{ NetBIOS = $NetBIOS FQDN = $FQDN Port = $FinalPort Scenario = $Scenario InstanceName = $InstanceName TargetDomain = $TargetDomain CrossForest = $CrossForest } } |