Find and correct SPN issues for SQL team
This commit is contained in:
111
SPooN.ps1
Normal file
111
SPooN.ps1
Normal 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 ==="
|
||||
Reference in New Issue
Block a user