@echo off setlocal EnableExtensions DisableDelayedExpansion cd /d "%~dp0" :MENU cls echo ============================================================ echo NETWORK SCANNER (PING + ARP MAC LOOKUP) echo ============================================================ echo. set /p "CIDR=Enter CIDR (e.g. 192.168.1.0/24): " if "%CIDR%"=="" goto MENU set /p "TOUT=Timeout ms [100]: " if "%TOUT%"=="" set "TOUT=100" set /p "CNT=Pings [1]: " if "%CNT%"=="" set "CNT=1" REM ============================================================ REM PARSE & VALIDATE REM ============================================================ for /f "tokens=1,2 delims=/" %%A in ("%CIDR%") do ( set "IP_ADDR=%%A" set "PREFIX=%%B" ) if "%PREFIX%"=="" set "PREFIX=24" REM Trim spaces/CR from prefix for /f "delims= " %%T in ("%PREFIX%") do set "PREFIX=%%T" set /a PNUM=%PREFIX% 2>nul if errorlevel 1 ( echo [Error] Prefix must be numeric. pause goto MENU ) if %PNUM% LSS 1 goto ERR_RANGE if %PNUM% GTR 30 goto ERR_RANGE for /f "tokens=1-4 delims=." %%A in ("%IP_ADDR%") do ( set "O1=%%A" set "O2=%%B" set "O3=%%C" set "O4=%%D" ) if "%O4%"=="" ( echo [Error] Invalid IP format. pause goto MENU ) for %%V in (%O1% %O2% %O3% %O4%) do ( if %%V LSS 0 goto ERR_RANGE if %%V GTR 255 goto ERR_RANGE ) REM ============================================================ REM CALCULATE MASK REM ============================================================ set "M1=0" set "M2=0" set "M3=0" set "M4=0" if %PNUM% LEQ 8 ( set /a "M1=256-(1<<(8-%PNUM%))" goto MASK_DONE ) set "M1=255" if %PNUM% LEQ 16 ( set /a "M2=256-(1<<(16-%PNUM%))" goto MASK_DONE ) set "M2=255" if %PNUM% LEQ 24 ( set /a "M3=256-(1<<(24-%PNUM%))" goto MASK_DONE ) set "M3=255" set /a "M4=256-(1<<(32-%PNUM%))" :MASK_DONE REM ============================================================ REM CALCULATE HOST COUNT REM ============================================================ set /a "HOSTS=(1<<(32-%PNUM%))-2" if "%HOSTS%"=="0" ( echo [Error] No usable hosts in this range. pause goto MENU ) REM ============================================================ REM CALCULATE NETWORK ADDRESS REM ============================================================ set /a "N1=O1&M1" set /a "N2=O2&M2" set /a "N3=O3&M3" set /a "N4=O4&M4" set "NETWORK_ADDR=%N1%.%N2%.%N3%.%N4%/%PNUM%" REM ============================================================ REM CALCULATE BROADCAST ADDRESS REM Broadcast = Network + wildcard mask REM Wildcard mask = 255 - subnet mask octet REM ============================================================ set /a "B1=N1+(255-M1)" set /a "B2=N2+(255-M2)" set /a "B3=N3+(255-M3)" set /a "B4=N4+(255-M4)" set "BROADCAST_ADDR=%B1%.%B2%.%B3%.%B4%" REM ============================================================ REM CALCULATE START IP REM Start IP = Network + 1 REM ============================================================ set /a S1=N1 set /a S2=N2 set /a S3=N3 set /a S4=N4+1 if %S4% GTR 255 ( set /a S4=0 set /a S3+=1 ) if %S3% GTR 255 ( set /a S3=0 set /a S2+=1 ) if %S2% GTR 255 ( set /a S2=0 set /a S1+=1 ) set "START_IP=%S1%.%S2%.%S3%.%S4%" REM ============================================================ REM CALCULATE END IP REM End IP = Broadcast - 1 REM ============================================================ set /a E1=B1 set /a E2=B2 set /a E3=B3 set /a E4=B4-1 if %E4% LSS 0 ( set /a E4=255 set /a E3-=1 ) if %E3% LSS 0 ( set /a E3=255 set /a E2-=1 ) if %E2% LSS 0 ( set /a E2=255 set /a E1-=1 ) set "END_IP=%E1%.%E2%.%E3%.%E4%" REM ============================================================ REM PREPARE OUTPUT FILE REM ============================================================ set "SAFE_IP=%IP_ADDR:.=_%" set "SAFE_IP=%SAFE_IP:/=_%" set "OUT_FILE=ping_%SAFE_IP%_p%PNUM%.txt" call :GET_TIME_CS START_CS set "START_STAMP=%DATE% %TIME%" echo. echo Network: %NETWORK_ADDR% echo Start IP: %START_IP% echo End IP: %END_IP% echo Broadcast: %BROADCAST_ADDR% echo Hosts: %HOSTS% echo Timeout: %TOUT% ms echo Pings: %CNT% echo File: %OUT_FILE% echo. echo Scanning... Please wait. echo. REM ============================================================ REM CREATE OUTPUT FILE ONLY IF IT DOES NOT EXIST REM Existing file is used as an accumulated inventory. REM ============================================================ if not exist "%OUT_FILE%" ( > "%OUT_FILE%" ( echo ============================================================ echo NETWORK SCANNER ACCUMULATED REPORT echo ============================================================ echo. echo File created;%START_STAMP% echo Initial CIDR;%CIDR% echo Initial network;%NETWORK_ADDR% echo Initial start IP;%START_IP% echo Initial end IP;%END_IP% echo Initial broadcast IP;%BROADCAST_ADDR% echo. echo ------------------------------------------------------------ echo UNIQUE HOST PAIRS echo ------------------------------------------------------------ echo IP;MAC ) ) REM ============================================================ REM INIT COUNTERS REM Start scan exactly from calculated Start IP REM ============================================================ set /a IP1=S1 set /a IP2=S2 set /a IP3=S3 set /a IP4=S4 set /a CUR=0 set /a ALIVE=0 set /a NEW_PAIRS=0 set /a SKIPPED_PAIRS=0 set /a PE=HOSTS/50 if %PE% LSS 1 set PE=1 REM ============================================================ REM SCAN LOOP REM The loop scans HOSTS addresses only: REM from Start IP to End IP. REM Broadcast IP is not included. REM ============================================================ setlocal EnableDelayedExpansion for /L %%I in (1,1,%HOSTS%) do ( set /a CUR+=1 set "CIP=!IP1!.!IP2!.!IP3!.!IP4!" ping -n %CNT% -w %TOUT% !CIP! >nul 2>&1 if !errorlevel! EQU 0 ( set /a ALIVE+=1 REM Clear MAC before every ARP lookup set "MAC=" REM Search MAC address in local ARP table for /f "tokens=1,2" %%A in ('arp -a') do ( if "%%A"=="!CIP!" set "MAC=%%B" ) if not defined MAC set "MAC=UNKNOWN" set "PAIR=!CIP!;!MAC!" REM ==================================================== REM CHECK IF EXACT IP;MAC PAIR ALREADY EXISTS REM If the pair exists, do not add it again. REM If the pair is new, append it to the accumulated file. REM ==================================================== findstr /x /c:"!PAIR!" "%OUT_FILE%" >nul 2>&1 if errorlevel 1 ( echo(!PAIR!>> "%OUT_FILE%" set /a NEW_PAIRS+=1 echo New: !CIP! MAC: !MAC! ) else ( set /a SKIPPED_PAIRS+=1 echo Existing: !CIP! MAC: !MAC! ) ) set /a MOD=CUR%%PE if !MOD! EQU 0 ( echo Progress: !CUR!/%HOSTS% Alive: !ALIVE! New: !NEW_PAIRS! Existing: !SKIPPED_PAIRS! ) set /a IP4+=1 if !IP4! GTR 255 ( set /a IP4=0 set /a IP3+=1 ) if !IP3! GTR 255 ( set /a IP3=0 set /a IP2+=1 ) if !IP2! GTR 255 ( set /a IP2=0 set /a IP1+=1 ) ) REM Save counter values before leaving local delayed expansion scope endlocal & ( set "ALIVE=%ALIVE%" set "NEW_PAIRS=%NEW_PAIRS%" set "SKIPPED_PAIRS=%SKIPPED_PAIRS%" ) REM ============================================================ REM CALCULATE SCAN TIME REM ============================================================ call :GET_TIME_CS END_CS set "END_STAMP=%DATE% %TIME%" set /a ELAPSED_CS=END_CS-START_CS REM Midnight rollover protection if %ELAPSED_CS% LSS 0 set /a ELAPSED_CS+=24*60*60*100 call :FORMAT_ELAPSED %ELAPSED_CS% ELAPSED_TEXT REM ============================================================ REM WRITE SCAN HISTORY ENTRY REM ============================================================ >> "%OUT_FILE%" ( echo. echo ------------------------------------------------------------ echo SCAN HISTORY ENTRY echo ------------------------------------------------------------ echo Started;%START_STAMP% echo Finished;%END_STAMP% echo Elapsed;%ELAPSED_TEXT% echo Input CIDR;%CIDR% echo Network;%NETWORK_ADDR% echo Start IP;%START_IP% echo End IP;%END_IP% echo Broadcast IP;%BROADCAST_ADDR% echo Broadcast excluded;Yes echo Timeout ms;%TOUT% echo Pings;%CNT% echo Hosts scanned;%HOSTS% echo Alive hosts in this scan;%ALIVE% echo New IP-MAC pairs added;%NEW_PAIRS% echo Existing IP-MAC pairs skipped;%SKIPPED_PAIRS% echo ============================================================ ) echo. echo ============================================================ echo Complete! echo Network: %NETWORK_ADDR% echo Start IP: %START_IP% echo End IP: %END_IP% echo Broadcast: %BROADCAST_ADDR% echo Alive hosts this scan: %ALIVE% echo New IP-MAC pairs added: %NEW_PAIRS% echo Existing pairs skipped: %SKIPPED_PAIRS% echo Time: %ELAPSED_TEXT% echo Results: %OUT_FILE% echo ============================================================ pause goto MENU REM ============================================================ REM ERROR HANDLER REM ============================================================ :ERR_RANGE echo [Error] Value out of range. Prefix must be 1-30, octets must be 0-255. pause goto MENU REM ============================================================ REM SUBROUTINE: GET CURRENT TIME IN CENTISECONDS REM ============================================================ :GET_TIME_CS set "T=%TIME: =0%" for /f "tokens=1-4 delims=:., " %%A in ("%T%") do ( set /a "%~1=((1%%A-100)*360000)+((1%%B-100)*6000)+((1%%C-100)*100)+(1%%D-100)" ) exit /b REM ============================================================ REM SUBROUTINE: FORMAT CENTISECONDS AS HH:MM:SS.CC REM ============================================================ :FORMAT_ELAPSED set /a _CS=%~1 set /a _H=_CS/360000 set /a _CS=_CS%%360000 set /a _M=_CS/6000 set /a _CS=_CS%%6000 set /a _S=_CS/100 set /a _C=_CS%%100 if %_H% LSS 10 set "_H=0%_H%" if %_M% LSS 10 set "_M=0%_M%" if %_S% LSS 10 set "_S=0%_S%" if %_C% LSS 10 set "_C=0%_C%" set "%~2=%_H%:%_M%:%_S%.%_C%" exit /b