Test-DNSServer.ps1
Niveau : Intermรฉdiaire
Vรฉrification complรจte d'un serveur DNS Windows.
Description
Ce script vรฉrifie l'รฉtat d'un serveur DNS Windows : - Service DNS et connectivitรฉ - Zones DNS et rรฉplication - Enregistrements critiques (SOA, NS, A) - Forwarders et rรฉsolution - Scavenging et statistiques
Prรฉrequis
- Systรจme : Windows Server 2016+ avec rรดle DNS
- PowerShell : Version 5.1 minimum
- Permissions : Droits administrateur sur le serveur DNS
- Modules :
DnsServer(installรฉ automatiquement avec le rรดle DNS)
Cas d'Usage
- Monitoring DNS : Surveillance quotidienne de la santรฉ du service DNS
- Troubleshooting rรฉsolution : Diagnostiquer les problรจmes de rรฉsolution de noms
- Audit zones AD-intรฉgrรฉes : Vรฉrifier la rรฉplication DNS dans Active Directory
- Performance : Analyser les temps de rรฉponse et statistiques de cache
Script
#Requires -Version 5.1
<#
.SYNOPSIS
Health check d'un serveur DNS Windows.
.DESCRIPTION
Vรฉrifie l'รฉtat complet d'un serveur DNS incluant
les zones, la rรฉplication, les forwarders et la rรฉsolution.
.PARAMETER DnsServer
Nom du serveur DNS (dรฉfaut: localhost).
.PARAMETER TestDomains
Domaines ร tester pour la rรฉsolution.
.PARAMETER CheckADIntegrated
Vรฉrifier les zones AD-intรฉgrรฉes.
.EXAMPLE
.\Test-DNSServer.ps1
Vรฉrifie le serveur DNS local.
.EXAMPLE
.\Test-DNSServer.ps1 -DnsServer "DC01" -CheckADIntegrated
Vรฉrifie un serveur DNS AD.
.NOTES
Author: ShellBook
Version: 1.0
#>
[CmdletBinding()]
param(
[Parameter()]
[string]$DnsServer = "localhost",
[Parameter()]
[string[]]$TestDomains = @("google.com", "microsoft.com", "cloudflare.com"),
[Parameter()]
[switch]$CheckADIntegrated
)
#region Functions
function Write-Check {
param(
[string]$Name,
[ValidateSet('Pass', 'Warn', 'Fail', 'Info')]
[string]$Status,
[string]$Message
)
$icons = @{
'Pass' = @('[OK] ', 'Green')
'Warn' = @('[WARN]', 'Yellow')
'Fail' = @('[FAIL]', 'Red')
'Info' = @('[INFO]', 'Cyan')
}
Write-Host $icons[$Status][0] -ForegroundColor $icons[$Status][1] -NoNewline
Write-Host " $Name" -NoNewline
if ($Message) { Write-Host " - $Message" -ForegroundColor Gray }
else { Write-Host "" }
switch ($Status) {
'Pass' { $script:passed++ }
'Warn' { $script:warnings++ }
'Fail' { $script:failed++ }
}
$script:total++
}
#endregion
#region Main
$script:total = 0
$script:passed = 0
$script:warnings = 0
$script:failed = 0
Write-Host ""
Write-Host ("=" * 65) -ForegroundColor Cyan
Write-Host " DNS SERVER HEALTH CHECK" -ForegroundColor Green
Write-Host ("=" * 65) -ForegroundColor Cyan
Write-Host " Server: $DnsServer"
Write-Host " Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Host ("-" * 65) -ForegroundColor Cyan
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 1: Service DNS
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Service DNS]" -ForegroundColor Cyan
$dnsService = Get-Service -Name DNS -ComputerName $DnsServer -ErrorAction SilentlyContinue
if ($dnsService -and $dnsService.Status -eq 'Running') {
Write-Check -Name "DNS Service" -Status Pass -Message "Running"
} else {
Write-Check -Name "DNS Service" -Status Fail -Message "Not running"
Write-Host "`n[FATAL] DNS service not running. Aborting." -ForegroundColor Red
exit 2
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 2: Connectivitรฉ DNS
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Connectivitรฉ]" -ForegroundColor Cyan
# Port 53 TCP
$tcp53 = Test-NetConnection -ComputerName $DnsServer -Port 53 -WarningAction SilentlyContinue
if ($tcp53.TcpTestSucceeded) {
Write-Check -Name "DNS TCP/53" -Status Pass
} else {
Write-Check -Name "DNS TCP/53" -Status Fail -Message "Port closed"
}
# Test UDP via query
try {
$udpTest = Resolve-DnsName -Name "localhost" -Server $DnsServer -DnsOnly -ErrorAction Stop
Write-Check -Name "DNS UDP/53" -Status Pass -Message "Responding"
}
catch {
Write-Check -Name "DNS UDP/53" -Status Fail -Message "Not responding"
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 3: Configuration serveur
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Configuration]" -ForegroundColor Cyan
try {
$dnsConfig = Get-DnsServer -ComputerName $DnsServer -ErrorAction Stop
# Recursion
if ($dnsConfig.ServerRecursion.Enable) {
Write-Check -Name "Recursion" -Status Info -Message "Enabled"
} else {
Write-Check -Name "Recursion" -Status Info -Message "Disabled"
}
# Cache
$cacheSettings = $dnsConfig.ServerCache
Write-Check -Name "Max Cache TTL" -Status Info -Message "$($cacheSettings.MaxTtl)"
# Scavenging
$scavenging = Get-DnsServerScavenging -ComputerName $DnsServer
if ($scavenging.ScavengingState) {
Write-Check -Name "Scavenging" -Status Pass -Message "Enabled (interval: $($scavenging.ScavengingInterval))"
} else {
Write-Check -Name "Scavenging" -Status Warn -Message "Disabled"
}
}
catch {
Write-Check -Name "Configuration" -Status Warn -Message "Could not retrieve: $_"
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 4: Forwarders
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Forwarders]" -ForegroundColor Cyan
try {
$forwarders = Get-DnsServerForwarder -ComputerName $DnsServer -ErrorAction Stop
if ($forwarders.IPAddress.Count -gt 0) {
Write-Check -Name "Forwarders configurรฉs" -Status Pass -Message "$($forwarders.IPAddress.Count) forwarder(s)"
foreach ($fw in $forwarders.IPAddress) {
# Tester chaque forwarder
try {
$fwTest = Resolve-DnsName -Name "google.com" -Server $fw.ToString() -DnsOnly -ErrorAction Stop
Write-Check -Name "Forwarder $fw" -Status Pass -Message "Responding"
}
catch {
Write-Check -Name "Forwarder $fw" -Status Fail -Message "Not responding"
}
}
} else {
Write-Check -Name "Forwarders" -Status Info -Message "None configured (root hints used)"
}
}
catch {
Write-Check -Name "Forwarders" -Status Warn -Message "Could not check"
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 5: Zones DNS
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Zones DNS]" -ForegroundColor Cyan
try {
$zones = Get-DnsServerZone -ComputerName $DnsServer -ErrorAction Stop
$primaryZones = $zones | Where-Object { $_.ZoneType -eq 'Primary' }
$secondaryZones = $zones | Where-Object { $_.ZoneType -eq 'Secondary' }
$stubZones = $zones | Where-Object { $_.ZoneType -eq 'Stub' }
$forwarderZones = $zones | Where-Object { $_.ZoneType -eq 'Forwarder' }
Write-Check -Name "Primary zones" -Status Info -Message "$($primaryZones.Count)"
Write-Check -Name "Secondary zones" -Status Info -Message "$($secondaryZones.Count)"
if ($CheckADIntegrated) {
$adIntegrated = $zones | Where-Object { $_.IsDsIntegrated }
Write-Check -Name "AD-Integrated zones" -Status Info -Message "$($adIntegrated.Count)"
}
# Vรฉrifier chaque zone primaire
foreach ($zone in $primaryZones | Where-Object { $_.ZoneName -ne 'TrustAnchors' }) {
# SOA record
try {
$soa = Get-DnsServerResourceRecord -ZoneName $zone.ZoneName -ComputerName $DnsServer -RRType SOA -ErrorAction Stop
Write-Check -Name "Zone $($zone.ZoneName)" -Status Pass -Message "SOA OK"
}
catch {
Write-Check -Name "Zone $($zone.ZoneName)" -Status Warn -Message "No SOA record"
}
}
# Zones secondaires - vรฉrifier le transfert
foreach ($zone in $secondaryZones) {
$zoneInfo = Get-DnsServerZone -Name $zone.ZoneName -ComputerName $DnsServer
if ($zoneInfo.ZoneTransferLastSuccessTime) {
$lastTransfer = $zoneInfo.ZoneTransferLastSuccessTime
$hoursSince = [math]::Round(((Get-Date) - $lastTransfer).TotalHours, 1)
if ($hoursSince -gt 24) {
Write-Check -Name "Secondary $($zone.ZoneName)" -Status Warn -Message "Last transfer: $hoursSince h ago"
} else {
Write-Check -Name "Secondary $($zone.ZoneName)" -Status Pass -Message "Last transfer: $hoursSince h ago"
}
}
}
}
catch {
Write-Check -Name "Zones DNS" -Status Fail -Message $_.Exception.Message
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 6: Rรฉsolution externe
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Rรฉsolution externe]" -ForegroundColor Cyan
foreach ($domain in $TestDomains) {
try {
$startTime = Get-Date
$result = Resolve-DnsName -Name $domain -Server $DnsServer -DnsOnly -ErrorAction Stop
$responseTime = [math]::Round(((Get-Date) - $startTime).TotalMilliseconds, 0)
if ($responseTime -gt 1000) {
Write-Check -Name "Resolve $domain" -Status Warn -Message "${responseTime}ms (slow)"
} else {
Write-Check -Name "Resolve $domain" -Status Pass -Message "${responseTime}ms"
}
}
catch {
Write-Check -Name "Resolve $domain" -Status Fail -Message "Failed"
}
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 7: Reverse lookup zones
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Reverse Lookup Zones]" -ForegroundColor Cyan
$reverseZones = $zones | Where-Object { $_.IsReverseLookupZone }
if ($reverseZones.Count -gt 0) {
Write-Check -Name "Reverse zones" -Status Pass -Message "$($reverseZones.Count) zone(s)"
} else {
Write-Check -Name "Reverse zones" -Status Warn -Message "None configured"
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CHECK 8: Statistiques
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n[Statistiques]" -ForegroundColor Cyan
try {
$stats = Get-DnsServerStatistics -ComputerName $DnsServer -ErrorAction Stop
$queryStats = $stats.Query2Statistics
Write-Host " Total queries: $($queryStats.TotalQueries)" -ForegroundColor Gray
Write-Host " Successful: $($queryStats.Standard)" -ForegroundColor Gray
Write-Host " Recursive: $($queryStats.Recursive)" -ForegroundColor Gray
$cacheStats = $stats.CacheStatistics
Write-Host " Cache hits: $($cacheStats.CacheHits)" -ForegroundColor Gray
Write-Host " Cache misses: $($cacheStats.CacheMisses)" -ForegroundColor Gray
Write-Check -Name "Statistics" -Status Pass -Message "Retrieved"
}
catch {
Write-Check -Name "Statistics" -Status Info -Message "Could not retrieve"
}
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# RรSUMร
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Write-Host "`n" + ("=" * 65) -ForegroundColor Cyan
Write-Host " RรSUMร" -ForegroundColor Green
Write-Host ("=" * 65) -ForegroundColor Cyan
Write-Host " Checks: $script:total total"
Write-Host " - " -NoNewline; Write-Host "Passed: $script:passed" -ForegroundColor Green
Write-Host " - " -NoNewline; Write-Host "Warnings: $script:warnings" -ForegroundColor Yellow
Write-Host " - " -NoNewline; Write-Host "Failed: $script:failed" -ForegroundColor Red
Write-Host ""
if ($script:failed -gt 0) {
Write-Host " DNS STATUS: CRITICAL" -ForegroundColor Red
exit 2
} elseif ($script:warnings -gt 0) {
Write-Host " DNS STATUS: DEGRADED" -ForegroundColor Yellow
exit 1
} else {
Write-Host " DNS STATUS: HEALTHY" -ForegroundColor Green
exit 0
}
#endregion
Utilisation
# Vรฉrifier le serveur DNS local
.\Test-DNSServer.ps1
# Serveur distant
.\Test-DNSServer.ps1 -DnsServer "DC01.domain.local"
# Avec vรฉrification AD-intรฉgrรฉe
.\Test-DNSServer.ps1 -DnsServer "DC01" -CheckADIntegrated
# Domaines de test personnalisรฉs
.\Test-DNSServer.ps1 -TestDomains @("internal.corp", "google.com")
Exemple de Sortie
=================================================================
DNS SERVER HEALTH CHECK
=================================================================
Server: DC01.corp.local
Date: 2025-12-01 18:32:15
-----------------------------------------------------------------
[Service DNS]
[OK] DNS Service - Running
[Connectivitรฉ]
[OK] DNS TCP/53
[OK] DNS UDP/53 - Responding
[Configuration]
[INFO] Recursion - Enabled
[INFO] Max Cache TTL - 1.00:00:00
[OK] Scavenging - Enabled (interval: 7.00:00:00)
[Forwarders]
[OK] Forwarders configurรฉs - 2 forwarder(s)
[OK] Forwarder 8.8.8.8 - Responding
[OK] Forwarder 1.1.1.1 - Responding
[Zones DNS]
[INFO] Primary zones - 4
[INFO] Secondary zones - 1
[INFO] AD-Integrated zones - 3
[OK] Zone corp.local - SOA OK
[OK] Zone internal.corp.local - SOA OK
[OK] Zone _msdcs.corp.local - SOA OK
[OK] Secondary partner.com - Last transfer: 2.3 h ago
[Rรฉsolution externe]
[OK] Resolve google.com - 32ms
[OK] Resolve microsoft.com - 45ms
[OK] Resolve cloudflare.com - 28ms
[Reverse Lookup Zones]
[OK] Reverse zones - 2 zone(s)
[Statistiques]
Total queries: 2847563
Successful: 2834127
Recursive: 1245789
Cache hits: 1847234
Cache misses: 987593
[OK] Statistics - Retrieved
=================================================================
RรSUMร
=================================================================
Checks: 19 total
- Passed: 15
- Warnings: 0
- Failed: 0
DNS STATUS: HEALTHY