Windows Server: Polling critical DNS entries for any changes or errors

If you have tier 1 services that are dependant on a few DNS records, then you may want a simple batch job to monitor these dns records for changes or deletion.

The script below contains an example list of DNS entries (replace these records for the ones you want to monitor).

@echo off
setlocal enabledelayedexpansion

REM ============================================================================
REM DNS Monitor Script for Windows Server
REM Purpose: Monitor DNS entries for changes every 15 minutes
REM Author: Andrew Baker
REM Version: 1.0
REM Date: August 13, 2018
REM ============================================================================

REM Configuration Variables
set "LOG_FILE=dns_monitor.log"
set "PREVIOUS_FILE=dns_previous.tmp"
set "CURRENT_FILE=dns_current.tmp"
set "CHECK_INTERVAL=900"

REM DNS Entries to Monitor (Comma Separated List)
REM Add or modify domains as needed
set "DNS_LIST=google.com,microsoft.com,github.com,stackoverflow.com,amazon.com,facebook.com,twitter.com,linkedin.com,youtube.com,cloudflare.com"

REM Initialize log file with header if it doesn't exist
if not exist "%LOG_FILE%" (
    echo DNS Monitor Log - Started on %DATE% %TIME% > "%LOG_FILE%"
    echo ============================================================================ >> "%LOG_FILE%"
    echo. >> "%LOG_FILE%"
)

:MAIN_LOOP
echo [%DATE% %TIME%] Starting DNS monitoring cycle...
echo [%DATE% %TIME%] INFO: Starting DNS monitoring cycle >> "%LOG_FILE%"

REM Clear current results file
if exist "%CURRENT_FILE%" del "%CURRENT_FILE%"

REM Process each DNS entry
for %%d in (%DNS_LIST%) do (
    call :CHECK_DNS "%%d"
)

REM Compare with previous results if they exist
if exist "%PREVIOUS_FILE%" (
    call :COMPARE_RESULTS
) else (
    echo [%DATE% %TIME%] INFO: First run - establishing baseline >> "%LOG_FILE%"
)

REM Copy current results to previous for next comparison
copy "%CURRENT_FILE%" "%PREVIOUS_FILE%" >nul 2>&1

echo [%DATE% %TIME%] DNS monitoring cycle completed. Next check in 15 minutes...
echo [%DATE% %TIME%] INFO: DNS monitoring cycle completed >> "%LOG_FILE%"
echo. >> "%LOG_FILE%"

REM Wait 15 minutes (900 seconds) before next check
timeout /t %CHECK_INTERVAL% /nobreak >nul

goto MAIN_LOOP

REM ============================================================================
REM Function: CHECK_DNS
REM Purpose: Resolve DNS entry and log results
REM Parameter: %1 = Domain name to check
REM ============================================================================
:CHECK_DNS
set "DOMAIN=%~1"
echo Checking DNS for: %DOMAIN%

REM Perform nslookup and capture results
nslookup "%DOMAIN%" > temp_dns.txt 2>&1

REM Check if nslookup was successful
if %ERRORLEVEL% equ 0 (
    REM Extract IP addresses from nslookup output
    for /f "tokens=2" %%i in ('findstr /c:"Address:" temp_dns.txt ^| findstr /v "#53"') do (
        set "IP_ADDRESS=%%i"
        echo %DOMAIN%,!IP_ADDRESS! >> "%CURRENT_FILE%"
        echo [%DATE% %TIME%] INFO: %DOMAIN% resolves to !IP_ADDRESS! >> "%LOG_FILE%"
    )
    
    REM Handle case where no IP addresses were found in successful lookup
    findstr /c:"Address:" temp_dns.txt | findstr /v "#53" >nul
    if !ERRORLEVEL! neq 0 (
        echo %DOMAIN%,RESOLUTION_ERROR >> "%CURRENT_FILE%"
        echo [%DATE% %TIME%] ERROR: %DOMAIN% - No IP addresses found in DNS response >> "%LOG_FILE%"
        type temp_dns.txt >> "%LOG_FILE%"
        echo. >> "%LOG_FILE%"
    )
) else (
    REM DNS resolution failed
    echo %DOMAIN%,DNS_FAILURE >> "%CURRENT_FILE%"
    echo [%DATE% %TIME%] ERROR: %DOMAIN% - DNS resolution failed >> "%LOG_FILE%"
    type temp_dns.txt >> "%LOG_FILE%"
    echo. >> "%LOG_FILE%"
)

REM Clean up temporary file
if exist temp_dns.txt del temp_dns.txt

goto :EOF

REM ============================================================================
REM Function: COMPARE_RESULTS
REM Purpose: Compare current DNS results with previous results
REM ============================================================================
:COMPARE_RESULTS
echo Comparing DNS results for changes...

REM Read previous results into memory
if exist "%PREVIOUS_FILE%" (
    for /f "tokens=1,2 delims=," %%a in (%PREVIOUS_FILE%) do (
        set "PREV_%%a=%%b"
    )
)

REM Compare current results with previous
for /f "tokens=1,2 delims=," %%a in (%CURRENT_FILE%) do (
    set "CURRENT_DOMAIN=%%a"
    set "CURRENT_IP=%%b"
    
    REM Get previous IP for this domain
    set "PREVIOUS_IP=!PREV_%%a!"
    
    if "!PREVIOUS_IP!"=="" (
        REM New domain added
        echo [%DATE% %TIME%] INFO: New domain added to monitoring: !CURRENT_DOMAIN! = !CURRENT_IP! >> "%LOG_FILE%"
    ) else if "!PREVIOUS_IP!" neq "!CURRENT_IP!" (
        REM DNS change detected
        echo [%DATE% %TIME%] WARNING: DNS change detected for !CURRENT_DOMAIN! >> "%LOG_FILE%"
        echo [%DATE% %TIME%] WARNING: Previous IP: !PREVIOUS_IP! >> "%LOG_FILE%"
        echo [%DATE% %TIME%] WARNING: Current IP:  !CURRENT_IP! >> "%LOG_FILE%"
        echo [%DATE% %TIME%] WARNING: *** INVESTIGATE DNS CHANGE *** >> "%LOG_FILE%"
        echo. >> "%LOG_FILE%"
        
        REM Also display warning on console
        echo.
        echo *** WARNING: DNS CHANGE DETECTED ***
        echo Domain: !CURRENT_DOMAIN!
        echo Previous: !PREVIOUS_IP!
        echo Current:  !CURRENT_IP!
        echo Check log file for details: %LOG_FILE%
        echo.
    )
)

REM Check for domains that disappeared from current results
for /f "tokens=1,2 delims=," %%a in (%PREVIOUS_FILE%) do (
    set "CHECK_DOMAIN=%%a"
    set "FOUND=0"
    
    for /f "tokens=1 delims=," %%c in (%CURRENT_FILE%) do (
        if "%%c"=="!CHECK_DOMAIN!" set "FOUND=1"
    )
    
    if "!FOUND!"=="0" (
        echo [%DATE% %TIME%] WARNING: Domain !CHECK_DOMAIN! no longer resolving or removed from monitoring >> "%LOG_FILE%"
    )
)

goto :EOF

REM ============================================================================
REM End of Script
REM ============================================================================

Leave a Reply

Your email address will not be published. Required fields are marked *