PowerShell investigation script: Investigate-ADDNS.ps1
What the script does
This script performs a comprehensive health check on a Windows Server that hosts both Active Directory Domain Services (AD DS) and DNS Server. It is designed to run directly on the target server as an Administrator.
Here is a summary of the checks it performs:
- Role & Service Validation
- Confirms the DNS Server service is installed, running, and set to automatic start.
- Confirms the server is recognized as a Domain Controller.
- Checks that AD Web Services (ADWS) is running.
- DNS Server Configuration
- Lists the IP addresses the DNS server is listening on.
- Checks if DNS forwarders are configured.
- Verifies that root hints are present.
- DNS Zones
- Enumerates forward and reverse lookup zones.
- Checks whether zones are Active Directory-integrated.
- Checks if aging and scavenging are enabled (to prevent stale record buildup).
- Critical AD DNS Records
- Resolves NS records for the domain.
- Resolves essential SRV records (
_ldap,_kerberos,_ldap._tcp.dc._msdcs, GC records). - Verifies the DC’s own A record resolves correctly.
- Provides advice to run
ipconfig /registerdnsand restart Netlogon if records are missing.
- DNS Client Settings
- Checks the network adapter DNS settings.
- Warns if
127.0.0.1is missing or if the DNS configuration looks incorrect for a DC.
- Resolution & Connectivity
- Tests external name resolution (e.g., Google, Microsoft) to verify forwarders/root hints work.
- Tests if TCP port 53 is responding locally.
- AD Replication
- Checks replication partner metadata. Since AD-integrated DNS stores data in AD, replication health directly impacts DNS consistency.
- Optionally runs
repadmin /showreplif available.
- DCDiag (Optional)
- If you use the
-IncludeDCDiagswitch, it runs targeteddcdiagtests for DNS, registration, and advertising.
- If you use the
- Event Logs (Optional)
- If you use the
-IncludeEventLogsswitch, it scans the DNS Server and Directory Service event logs for errors and critical events within the last day (configurable).
- If you use the
- Remediation Advice
- At the end, it analyzes the results and prints specific PowerShell or command-line remediation suggestions based on what failed.
How to run it
Open an elevated PowerShell window on the DC/DNS server and run:
powershell
# Basic investigation
.\Investigate-ADDNS.ps1
# Include DCDiag and Event Log checks
.\Investigate-ADDNS.ps1 -IncludeDCDiag -IncludeEventLogs
# Custom log/report paths
.\Investigate-ADDNS.ps1 -LogPath "C:\Logs\DNS_Check.log" -ReportPath "C:\Logs\DNS_Check.csv"
Output
- Console output: Color-coded status messages and a summary table.
- Log file: A timestamped
.logfile with all details. - CSV report: A structured
.csvfile you can open in Excel for review or documentation.
Powershell Script (Investigate-ADDNS.ps1) Below
<#
.SYNOPSIS
AD DNS Health Investigation Script
.DESCRIPTION
Performs comprehensive diagnostic checks on a Windows Server running AD DS and DNS
to identify common DNS configuration, replication, and resolution issues.
.NOTES
Run as Administrator / Domain Admin on the target DC/DNS server.
Requires RSAT-DNS-Server tools on some checks if run remotely.
#>
[CmdletBinding()]
param(
[string]$LogPath = “C:\Temp\ADDNS_Investigation_$(Get-Date -Format ‘yyyyMMdd_HHmmss’).log”,
[string]$ReportPath = “C:\Temp\ADDNS_Investigation_$(Get-Date -Format ‘yyyyMMdd_HHmmss’).csv”,
[switch]$IncludeEventLogs,
[switch]$IncludeDCDiag,
[int]$EventLogDays = 1
)
#Requires -RunAsAdministrator
#region Helper Functions
function Write-Log {
param([string]$Message, [ValidateSet(‘Info’,’Warning’,’Error’,’Success’)][string]$Level = ‘Info’)
$ts = Get-Date -Format “yyyy-MM-dd HH:mm:ss”
$line = “[$ts] [$Level] $Message”
switch ($Level) {
‘Warning’ { Write-Host $line -ForegroundColor Yellow }
‘Error’ { Write-Host $line -ForegroundColor Red }
‘Success’ { Write-Host $line -ForegroundColor Green }
default { Write-Host $line -ForegroundColor Cyan }
}
$line | Out-File -FilePath $LogPath -Append -Encoding UTF8 -ErrorAction SilentlyContinue
}
function Test-IsDomainController {
try {
$role = (Get-ItemProperty “HKLM:\SYSTEM\CurrentControlSet\Control\ProductOptions” -Name ProductType).ProductType
return ($role -eq “LanmanNT”)
} catch { return $false }
}
function Add-Result {
param([string]$Category,[string]$Test,[string]$Result,[string]$Details)
$script:Results += [PSCustomObject]@{
Timestamp = Get-Date -Format “yyyy-MM-dd HH:mm:ss”
Category = $Category
Test = $Test
Result = $Result
Details = $Details
}
}
$script:Results = @()
#endregion
#region Initialization
$Host.UI.RawUI.WindowTitle = “AD DNS Health Investigation”
if (-not (Test-Path (Split-Path $LogPath))) { New-Item -ItemType Directory -Path (Split-Path $LogPath) -Force | Out-Null }
Write-Log “========== AD DNS Investigation Started ==========”
Write-Log “Server: $env:COMPUTERNAME”
Write-Log “User: $env:USERDOMAIN$env:USERNAME”
Write-Log “Log file: $LogPath”
#endregion
#region 1. Basic Server & Role Validation
Write-Log “— Checking Server Roles and Prerequisites —“
$dnsService = Get-Service -Name DNS -ErrorAction SilentlyContinue
if ($dnsService) {
$status = $dnsService.Status
$startType = (Get-WmiObject Win32_Service -Filter “Name=’DNS'”).StartMode
Write-Log “DNS Service Status: $status (StartType: $startType)”
if ($status -eq ‘Running’) {
Add-Result -Category “Services” -Test “DNS Service” -Result “PASS” -Details “DNS service is running (Start: $startType)”
} else {
Add-Result -Category “Services” -Test “DNS Service” -Result “FAIL” -Details “DNS service is NOT running. Status: $status, StartType: $startType”
}
} else {
Write-Log “DNS Server role does not appear to be installed.” “Error”
Add-Result -Category “Services” -Test “DNS Service” -Result “FAIL” -Details “DNS service not found”
}
$isDC = Test-IsDomainController
Write-Log “Is Domain Controller: $isDC”
Add-Result -Category “Server” -Test “DC Role Check” -Result $(if($isDC){“PASS”}else{“WARNING”}) -Details “ProductType indicates DC status: $isDC”
try {
$adws = Get-Service -Name ADWS -ErrorAction Stop
Write-Log “AD Web Services: $($adws.Status)”
Add-Result -Category “Services” -Test “ADWS” -Result $(if($adws.Status -eq ‘Running’){“PASS”}else{“FAIL”}) -Details “Status: $($adws.Status)”
} catch {
Write-Log “AD Web Services not found.” “Warning”
Add-Result -Category “Services” -Test “ADWS” -Result “FAIL” -Details “ADWS service not found”
}
#endregion
#region 2. DNS Server Configuration
Write-Log “— Investigating DNS Server Configuration —“
try {
$dnsServer = Get-DnsServer -ErrorAction Stop
Write-Log “DNS Server ComputerName: $($dnsServer.ComputerName)”
Write-Log “Listening IP Addresses: $($dnsServer.ListeningIPAddress -join ‘, ‘)”
Write-Log “Forwarders: $((Get-DnsServerForwarder).IPAddress.IPAddress -join ‘, ‘)”
$forwarders = Get-DnsServerForwarder
if ($forwarders.IPAddress) {
Add-Result -Category "DNS Config" -Test "Forwarders Configured" -Result "INFO" -Details "Forwarders: $($forwarders.IPAddress.IPAddress -join ', ')"
} else {
Add-Result -Category "DNS Config" -Test "Forwarders Configured" -Result "WARNING" -Details "No DNS forwarders configured. Root hints will be used."
}
if ($dnsServer.ListeningIPAddress.Count -eq 0) {
Add-Result -Category "DNS Config" -Test "Listening IPs" -Result "FAIL" -Details "DNS server is not listening on any IP addresses."
} else {
Add-Result -Category "DNS Config" -Test "Listening IPs" -Result "PASS" -Details "Listening on: $($dnsServer.ListeningIPAddress -join ', ')"
}
# Root hints check
$rootHints = Get-DnsServerRootHint
if ($rootHints.Count -eq 0) {
Add-Result -Category "DNS Config" -Test "Root Hints" -Result "FAIL" -Details "No root hints configured."
} else {
Add-Result -Category "DNS Config" -Test "Root Hints" -Result "PASS" -Details "$($rootHints.Count) root hints present."
}
} catch {
Write-Log “Failed to retrieve DNS server configuration: $” “Error”
Add-Result -Category “DNS Config” -Test “DNS Config Retrieval” -Result “FAIL” -Details $.Exception.Message
}
#endregion
#region 3. DNS Zones – AD Integrated Check
Write-Log “— Investigating DNS Zones —“
try {
$zones = Get-DnsServerZone | Where-Object { $.IsReverseLookupZone -eq $false -or $.ZoneType -eq ‘Forwarder’ -or $.ZoneName -match ‘in-addr.arpa’ }
$forwardZones = Get-DnsServerZone | Where-Object { $.IsReverseLookupZone -eq $false -and $.ZoneType -ne ‘Stub’ }
$revZones = Get-DnsServerZone | Where-Object { $.IsReverseLookupZone -eq $true }
foreach ($zone in $forwardZones) {
$zoneName = $zone.ZoneName
$zoneType = $zone.ZoneType
$isDsIntegrated = $zone.IsDsIntegrated
$dynamicUpdate = $zone.DynamicUpdate
$zoneStatus = if ($zone.ZoneType -eq 'Primary' -and $isDsIntegrated) { "PASS" } else { "INFO" }
Write-Log "Zone: $zoneName | Type: $zoneType | DS-Integrated: $isDsIntegrated | DynamicUpdate: $dynamicUpdate"
Add-Result -Category "DNS Zones" -Test "Zone: $zoneName" -Result $zoneStatus -Details "Type=$zoneType, DSIntegrated=$isDsIntegrated, DynamicUpdate=$dynamicUpdate"
# Check scavenging / aging
try {
$aging = Get-DnsServerZoneAging -ZoneName $zoneName -ErrorAction Stop
Write-Log " -> Aging enabled: $($aging.AgingEnabled), NoRefreshInterval: $($aging.NoRefreshInterval.Hours)h, RefreshInterval: $($aging.RefreshInterval.Hours)h"
if (-not $aging.AgingEnabled) {
Add-Result -Category "DNS Zones" -Test "Scavenging on $zoneName" -Result "WARNING" -Details "Aging/Scavenging is NOT enabled. Stale records may accumulate."
}
} catch {
Write-Log " -> Could not retrieve aging settings for $zoneName" "Warning"
}
}
if ($revZones.Count -eq 0) {
Write-Log "No reverse lookup zones found." "Warning"
Add-Result -Category "DNS Zones" -Test "Reverse Lookup Zones" -Result "WARNING" -Details "No reverse lookup zones detected."
} else {
foreach ($rz in $revZones) {
Write-Log "Reverse Zone: $($rz.ZoneName) | Type: $($rz.ZoneType) | DSIntegrated: $($rz.IsDsIntegrated)"
}
Add-Result -Category "DNS Zones" -Test "Reverse Lookup Zones" -Result "PASS" -Details "$($revZones.Count) reverse lookup zone(s) present."
}
} catch {
Write-Log “Failed to enumerate DNS zones: $” “Error”
Add-Result -Category “DNS Zones” -Test “Zone Enumeration” -Result “FAIL” -Details $.Exception.Message
}
#endregion
#region 4. Critical AD DNS Records
Write-Log “— Checking Critical AD DNS Records —“
try {
$domainName = (Get-ADDomain).DNSRoot
$dcName = $env:COMPUTERNAME
$dcIp = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $.IPAddress -notlike ‘127.*’ -and $.IPAddress -notlike ‘169.254.*’ } | Select-Object -First 1).IPAddress
Write-Log "Domain: $domainName"
Write-Log "DC Name: $dcName"
Write-Log "DC IPv4: $dcIp"
# NS records for domain
try {
$nsRecords = Resolve-DnsName -Name $domainName -Type NS -ErrorAction Stop
$nsList = ($nsRecords | Where-Object { $_.QueryType -eq 'NS' }).NameHost -join ', '
Write-Log "NS Records for $domainName : $nsList"
Add-Result -Category "DNS Records" -Test "NS Records" -Result "PASS" -Details "NS records: $nsList"
} catch {
Add-Result -Category "DNS Records" -Test "NS Records" -Result "FAIL" -Details "Cannot resolve NS records for $domainName : $_"
}
# LDAP/GC SRV records
$srvTests = @(
"_ldap._tcp.$domainName",
"_kerberos._tcp.$domainName",
"_ldap._tcp.dc._msdcs.$domainName",
"_ldap._tcp.gc._msdcs.$((Get-ADDomain).Forest)"
)
foreach ($srv in $srvTests) {
try {
$srvResult = Resolve-DnsName -Name $srv -Type SRV -ErrorAction Stop
$targets = ($srvResult | Where-Object { $_.QueryType -eq 'SRV' }).NameTarget -join ', '
Write-Log "SRV OK: $srv -> $targets" "Success"
Add-Result -Category "DNS Records" -Test "SRV: $srv" -Result "PASS" -Details "Targets: $targets"
} catch {
Write-Log "SRV FAIL: $srv -> $_" "Error"
Add-Result -Category "DNS Records" -Test "SRV: $srv" -Result "FAIL" -Details $_.Exception.Message
}
}
# A record for this DC
try {
$aRec = Resolve-DnsName -Name "$dcName.$domainName" -Type A -ErrorAction Stop
$resolvedIp = ($aRec | Where-Object { $_.QueryType -eq 'A' }).IPAddress
Write-Log "A record for $dcName.$domainName resolves to $resolvedIp" "Success"
Add-Result -Category "DNS Records" -Test "DC A Record" -Result "PASS" -Details "Resolves to: $resolvedIp"
} catch {
Write-Log "A record for $dcName.$domainName FAILED to resolve." "Error"
Add-Result -Category "DNS Records" -Test "DC A Record" -Result "FAIL" -Details "Cannot resolve $dcName.$domainName"
}
# Register this DC's records test
try {
$ipConfig = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter "IPEnabled = True"
foreach ($adapter in $ipConfig) {
$adapter.SetDNSDomain($domainName) | Out-Null
}
# Note: ipconfig /registerdns is non-destructive and re-registers DC DNS records
Write-Log "Consider running 'ipconfig /registerdns' if SRV/A records are missing." "Warning"
Add-Result -Category "DNS Records" -Test "Registration Advice" -Result "INFO" -Details "Run 'ipconfig /registerdns' and restart Netlogon if records are missing."
} catch {
# non-critical
}
} catch {
Write-Log “Error during DNS record checks: $_” “Error”
}
#endregion
#region 5. DNS Client / Adapter Configuration on DC
Write-Log “— Checking DNS Client Settings on DC —“
$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter “IPEnabled = True”
$loopbackFound = $false
$properDnsConfigured = $false
foreach ($adapter in $adapters) {
$dnsServers = $adapter.DNSServerSearchOrder
$desc = $adapter.Description
Write-Log “Adapter: $desc | DNS Servers: $($dnsServers -join ‘, ‘)”
if ($dnsServers -contains '127.0.0.1') {
$loopbackFound = $true
}
# Best practice: DC should point to itself (and another DC) for DNS
if ($dnsServers -contains (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notlike '127.*' -and $_.IPAddress -notlike '169.254.*' } | Select-Object -First 1).IPAddress) {
$properDnsConfigured = $true
}
}
if ($loopbackFound) {
Add-Result -Category “DNS Client” -Test “Loopback in DNS” -Result “INFO” -Details “127.0.0.1 found in DNS settings. Ensure another DC IP is also configured as secondary.”
} else {
Add-Result -Category “DNS Client” -Test “Loopback in DNS” -Result “WARNING” -Details “127.0.0.1 not found. DCs should typically point to themselves for DNS registration.”
}
Add-Result -Category “DNS Client” -Test “Adapter DNS Config” -Result $(if($properDnsConfigured){“PASS”}else{“WARNING”}) -Details “Review DNS server order on network adapters.”
#endregion
#region 6. DNS Resolution & Forwarder Tests
Write-Log “— Performing External DNS Resolution Tests —“
$testHosts = @(“www.google.com“, “microsoft.com”, “msdcs.$((Get-ADDomain).DNSRoot)”)
foreach ($h in $testHosts) {
try {
$res = Resolve-DnsName -Name $h -Type A -ErrorAction Stop -ErrorVariable err
$ip = ($res | Select-Object -First 1).IPAddress
Write-Log “Resolution OK: $h -> $ip” “Success”
Add-Result -Category “Resolution” -Test “Resolve $h” -Result “PASS” -Details “Resolved to $ip”
} catch {
Write-Log “Resolution FAIL: $h -> $” “Error”
Add-Result -Category “Resolution” -Test “Resolve $h” -Result “FAIL” -Details $_.Exception.Message
}
}
Test DNS server on port 53
$localIp = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $.IPAddress -notlike ‘127.*’ -and $.IPAddress -notlike ‘169.254.*’ } | Select-Object -First 1).IPAddress
try {
$testDns = Test-NetConnection -ComputerName $localIp -Port 53 -WarningAction SilentlyContinue
if ($testDns.TcpTestSucceeded) {
Write-Log “DNS TCP/53 responding on $localIp” “Success”
Add-Result -Category “Connectivity” -Test “DNS Port 53” -Result “PASS” -Details “TCP port 53 is reachable on $localIp”
} else {
Write-Log “DNS TCP/53 NOT responding on $localIp” “Error”
Add-Result -Category “Connectivity” -Test “DNS Port 53” -Result “FAIL” -Details “TCP port 53 is not responding.”
}
} catch {
Add-Result -Category “Connectivity” -Test “DNS Port 53” -Result “FAIL” -Details $_.Exception.Message
}
#endregion
#region 7. AD Replication & DS-Integrated DNS
Write-Log “— Checking AD Replication (impacts AD-Integrated DNS) —“
try {
Import-Module ActiveDirectory -ErrorAction Stop
$replSummary = Get-ADReplicationPartnerMetadata -Target “$env:COMPUTERNAME” -Partition * -ErrorAction SilentlyContinue
if (-not $replSummary) {
# Single DC environment
Write-Log “No replication partners found. This may be a single-DC environment.” “Warning”
Add-Result -Category “AD Replication” -Test “Replication Partners” -Result “INFO” -Details “No replication partners detected. Single DC or replication health issue.”
} else {
foreach ($partner in $replSummary) {
$lastRep = $partner.LastReplicationSuccess
$partnerServer = $partner.Partner
$partition = $partner.Partition
$hoursAgo = (Get-Date) – $lastRep
Write-Log “Replication: $partition with $partnerServer | Last Success: $lastRep ($([math]::Round($hoursAgo.TotalHours,1)) hours ago)”
if ($hoursAgo.TotalHours -gt 24) {
Add-Result -Category “AD Replication” -Test “Repl: $partition” -Result “FAIL” -Details “Last success was $([math]::Round($hoursAgo.TotalHours,1)) hours ago (>24h).”
} else {
Add-Result -Category “AD Replication” -Test “Repl: $partition” -Result “PASS” -Details “Last success $([math]::Round($hoursAgo.TotalHours,1)) hours ago.”
}
}
}
# Check for replication errors via repadmin (if available)
if (Get-Command repadmin.exe -ErrorAction SilentlyContinue) {
$repadminOut = & repadmin.exe /showrepl /csv 2>$null
if ($repadminOut) {
Write-Log "Repadmin /showrepl data collected (review manually if needed)." "Info"
Add-Result -Category "AD Replication" -Test "Repadmin" -Result "INFO" -Details "repadmin /showrepl executed. Check CSV output manually."
}
}
} catch {
Write-Log “Could not evaluate AD replication: $” “Warning”
Add-Result -Category “AD Replication” -Test “Replication Check” -Result “WARNING” -Details $.Exception.Message
}
#endregion
#region 8. DCDiag DNS Tests
if ($IncludeDCDiag) {
Write-Log “— Running DCDiag (DNS-focused) —“
if (Get-Command dcdiag.exe -ErrorAction SilentlyContinue) {
$dcdiagTests = @(“DNS”, “DnsReg”, “DsGetDc”, “Advertising”, “FsmoCheck”)
foreach ($t in $dcdiagTests) {
Write-Log “Running dcdiag /test:$t …”
$output = & dcdiag.exe /test:$t /q 2>&1
$outputStr = $output | Out-String
if ($outputStr -match “failed|error|fail” -or $LASTEXITCODE -ne 0) {
Write-Log “DCDiag /test:$t detected issues.” “Error”
Add-Result -Category “DCDiag” -Test “dcdiag /test:$t” -Result “FAIL” -Details ($outputStr.Substring(0,[Math]::Min(500,$outputStr.Length)))
} else {
Write-Log “DCDiag /test:$t passed.” “Success”
Add-Result -Category “DCDiag” -Test “dcdiag /test:$t” -Result “PASS” -Details “No errors reported.”
}
}
} else {
Write-Log “dcdiag.exe not found. Skipping DCDiag tests.” “Warning”
Add-Result -Category “DCDiag” -Test “DCDiag Availability” -Result “WARNING” -Details “dcdiag.exe not available.”
}
} else {
Write-Log “Skipping DCDiag tests (use -IncludeDCDiag to enable).” “Info”
}
#endregion
#region 9. Event Logs
if ($IncludeEventLogs) {
Write-Log “— Collecting DNS and Directory Service Event Log Errors (last $EventLogDays day(s)) —“
$startTime = (Get-Date).AddDays(-$EventLogDays)
$dnsEvents = Get-WinEvent -FilterHashtable @{LogName='DNS Server'; Level=1,2; StartTime=$startTime} -ErrorAction SilentlyContinue
$dsEvents = Get-WinEvent -FilterHashtable @{LogName='Directory Service'; Level=1,2; StartTime=$startTime} -ErrorAction SilentlyContinue
if ($dnsEvents) {
Write-Log "Found $($dnsEvents.Count) DNS Server error/critical event(s)." "Error"
$dnsEvents | Select-Object -First 5 | ForEach-Object {
Write-Log " DNS Event ID $($_.Id) at $($_.TimeCreated): $($_.Message.Substring(0,[Math]::Min(200,$_.Message.Length)))..." "Error"
}
Add-Result -Category "Event Logs" -Test "DNS Server Errors" -Result "FAIL" -Details "$($dnsEvents.Count) error/critical events in last $EventLogDays day(s)."
} else {
Write-Log "No DNS Server error/critical events in last $EventLogDays day(s)." "Success"
Add-Result -Category "Event Logs" -Test "DNS Server Errors" -Result "PASS" -Details "No error/critical events found."
}
if ($dsEvents) {
Write-Log "Found $($dsEvents.Count) Directory Service error/critical event(s)." "Error"
Add-Result -Category "Event Logs" -Test "Directory Service Errors" -Result "FAIL" -Details "$($dsEvents.Count) error/critical events in last $EventLogDays day(s)."
} else {
Write-Log "No Directory Service error/critical events in last $EventLogDays day(s)." "Success"
Add-Result -Category "Event Logs" -Test "Directory Service Errors" -Result "PASS" -Details "No error/critical events found."
}
} else {
Write-Log “Skipping Event Log analysis (use -IncludeEventLogs to enable).” “Info”
}
#endregion
#region 10. Scavenging & Stale Records Summary
Write-Log “— Checking Server-Level Scavenging —“
try {
$scavenging = Get-DnsServerScavenging
Write-Log “Scavenging Enabled: $($scavenging.ScavengingEnabled), Scavenging Interval: $($scavenging.ScavengingInterval)”
if (-not $scavenging.ScavengingEnabled) {
Add-Result -Category “DNS Maintenance” -Test “Server Scavenging” -Result “WARNING” -Details “Automatic scavenging is disabled at server level.”
} else {
Add-Result -Category “DNS Maintenance” -Test “Server Scavenging” -Result “PASS” -Details “Scavenging enabled. Interval: $($scavenging.ScavengingInterval)”
}
} catch {
Write-Log “Could not retrieve scavenging settings: $_” “Warning”
}
#endregion
#region 11. Common Remediation Advice Summary
Write-Log “— Generating Remediation Advice —“
$remediation = @()
$failures = $script:Results | Where-Object { $.Result -eq ‘FAIL’ }
$warnings = $script:Results | Where-Object { $.Result -eq ‘WARNING’ }
if ($failures | Where-Object { $.Test -eq ‘DNS Service’ }) {
$remediation += “DNS Service is not running. Run: Start-Service DNS; Set-Service DNS -StartupType Automatic”
}
if ($warnings | Where-Object { $.Test -like ‘Scavenging‘ }) {
$remediation += “Enable scavenging: Set-DnsServerScavenging -ScavengingEnabled `$true -ScavengingInterval 7.00:00:00”
}
if ($failures | Where-Object { $.Category -eq ‘DNS Records’ -and $.Test -like ‘SRV:*’ }) {
$remediation += “Missing SRV records. Run: ipconfig /registerdns ; then restart-service Netlogon”
}
if ($failures | Where-Object { $.Category -eq ‘AD Replication’ }) {
$remediation += “Replication issues detected. Investigate with: repadmin /replsummary and repadmin /showreps”
}
if ($warnings | Where-Object { $.Test -eq ‘Forwarders Configured’ }) {
$remediation += “No forwarders configured. If external resolution is needed, add via DNS console or Set-DnsServerForwarder.”
}
if ($remediation.Count -gt 0) {
Write-Log “n========== REMEDIATION SUGGESTIONS ==========" "Warning" $remediation | ForEach-Object { Write-Log $_ "Warning" } } else { Write-Log "nNo critical remediation suggestions generated. Review INFO/WARNING items above.” “Success”
}
#endregion
#region Export & Finalize
$script:Results | Export-Csv -Path $ReportPath -NoTypeInformation -Encoding UTF8 -Force
Write-Log “`n========== Investigation Complete ==========”
Write-Log “CSV Report: $ReportPath”
Write-Log “Log File: $LogPath”
Write-Log “Total Checks: $($script:Results.Count)”
Write-Log “Failures: $($failures.Count) | Warnings: $($warnings.Count) | Pass/Info: $(($script:Results | Where-Object {$_.Result -in ‘PASS’,’INFO’}).Count)”
Also output summary to console as a table
$script:Results | Format-Table -AutoSize | Out-String | Write-Host
#endregion