Find and correct SPN issues for SQL team

This commit is contained in:
2025-09-24 03:02:21 +00:00
parent ebb11455cd
commit a65eb6f4b4

111
SPooN.ps1 Normal file
View File

@@ -0,0 +1,111 @@
param(
[Parameter(Mandatory = $true)]
[string]$MachineName,
[Parameter(Mandatory = $true)]
[string]$ServiceAccount,
[int]$SqlPort = 1433,
[string[]]$HadrListeners
)
Import-Module ActiveDirectory
Write-Host "=== MSSQLSvc + HADR SPN Validation Tool ===" -ForegroundColor Cyan
Write-Host "Machine: $MachineName"
Write-Host "Service Account: $ServiceAccount"
Write-Host "SQL Port: $SqlPort"
if ($HadrListeners) {
Write-Host "HADR Listener(s): $($HadrListeners -join ', ')"
}
Write-Host "-------------------------------------------"
# Get domain FQDN
$domainFQDN = (Get-ADDomain).DNSRoot
# Lookup service account (user or computer)
try {
$svcObj = Get-ADUser -Identity $ServiceAccount -Properties ServicePrincipalName -ErrorAction Stop
} catch {
try {
$svcObj = Get-ADComputer -Identity $ServiceAccount -Properties ServicePrincipalName -ErrorAction Stop
} catch {
Write-Host "ERROR: Service account '$ServiceAccount' not found in AD." -ForegroundColor Red
exit
}
}
# Build expected MSSQLSvc SPNs for machine and HADR listeners
$namesToCheck = @($MachineName)
if ($HadrListeners) {
$namesToCheck += $HadrListeners
}
$expectedSPNs = foreach ($name in $namesToCheck) {
"MSSQLSvc/${name}.${domainFQDN}:$SqlPort"
"MSSQLSvc/${name}:$SqlPort"
}
Write-Host "`nExpected MSSQLSvc SPNs:" -ForegroundColor Yellow
$expectedSPNs | ForEach-Object { Write-Host " $_" }
# Case-insensitive missing SPN check (fixed grouping)
$missingSPNs = $expectedSPNs | Where-Object {
$expectedLower = $_.ToLower()
-not (( $svcObj.ServicePrincipalName | ForEach-Object { $_.ToLower() } ) -contains $expectedLower)
}
if ($missingSPNs) {
Write-Host "`n[!] Missing MSSQLSvc SPNs on service account:" -ForegroundColor Red
$missingSPNs | ForEach-Object { Write-Host " $_" -ForegroundColor Red }
$addPrompt = Read-Host "`nDo you want to add the missing SPNs now? (Y/N)"
if ($addPrompt -match '^[Yy]$') {
foreach ($spn in $missingSPNs) {
Write-Host "Adding SPN: $spn" -ForegroundColor Green
# Use -S to avoid duplicates, requires running as an account with permission
setspn -S $spn $ServiceAccount
}
Write-Host "`n[OK] Missing SPNs have been added." -ForegroundColor Green
} else {
Write-Host "Skipping SPN creation." -ForegroundColor Yellow
}
} else {
Write-Host "`n[OK] All expected MSSQLSvc SPNs are present." -ForegroundColor Green
}
# Pull all SPNs in the domain
$allSPNs = Get-ADObject -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName |
ForEach-Object {
foreach ($spn in $_.ServicePrincipalName) {
[PSCustomObject]@{
SPN = $spn
ADObject = $_.SamAccountName
DN = $_.DistinguishedName
}
}
}
# Check for duplicates of MSSQLSvc SPNs
Write-Host "`nChecking for duplicate MSSQLSvc SPNs in the domain..." -ForegroundColor Yellow
foreach ($spn in $svcObj.ServicePrincipalName | Where-Object { $_ -like "MSSQLSvc/*" }) {
$owners = $allSPNs | Where-Object { $_.SPN -eq $spn }
if ($owners.Count -gt 1) {
Write-Host "[DUPLICATE] SPN '$spn' is owned by multiple objects:" -ForegroundColor Red
$owners | ForEach-Object { Write-Host " -> $($_.ADObject) ($($_.DN))" }
}
}
# Check for MSSQLSvc SPNs on service account that aren't expected
$expectedLowerList = $expectedSPNs | ForEach-Object { $_.ToLower() }
$wrongSPNs = $svcObj.ServicePrincipalName | Where-Object {
$_ -like "MSSQLSvc/*" -and ($_.ToLower() -notin $expectedLowerList)
}
if ($wrongSPNs) {
Write-Host "`n[!] Warning: Service account has MSSQLSvc SPNs not in expected list:" -ForegroundColor Red
$wrongSPNs | ForEach-Object { Write-Host " $_" }
} else {
Write-Host "`n[OK] No unexpected MSSQLSvc SPNs found." -ForegroundColor Green
}
Write-Host "`n=== MSSQLSvc + HADR SPN Check Complete ==="