111 lines
3.9 KiB
PowerShell
111 lines
3.9 KiB
PowerShell
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 ===" |