@echo off
setlocal EnableExtensions EnableDelayedExpansion

REM ============================================================
REM Ping sweep for 10.255.0.0/16 with ARP MAC lookup
REM Saves alive IP addresses and MAC addresses to a text file.
REM
REM Network:
REM   10.255.0.0/16
REM
REM Scan range:
REM   10.255.0.1 - 10.255.255.254
REM
REM Optional arguments:
REM   ping_10_255_16_with_mac.bat 100 1
REM   where:
REM     100 = timeout in ms
REM     1   = ping count
REM ============================================================

cd /d "%~dp0"

set "OUT_FILE=ping_success_10_255_16.txt"

set "NET_A=10"
set "NET_B=255"

REM Default ping settings
set "TIMEOUT_MS=100"
set "PING_COUNT=1"

REM Optional arguments:
REM   %1 = timeout in ms
REM   %2 = ping count
if not "%~1"=="" set "TIMEOUT_MS=%~1"
if not "%~2"=="" set "PING_COUNT=%~2"

REM Progress settings
set "TOTAL=65534"
set "BAR_WIDTH=30"
set "ALIVE_COUNT=0"
set "CURRENT=0"

REM Progress output frequency.
REM 256 = one progress update per /24 block.
set "PRINT_EVERY=256"

REM Planned time calculation.
set /a PLANNED_SECONDS=TOTAL*PING_COUNT*TIMEOUT_MS/1000
set /a PLANNED_HOURS=PLANNED_SECONDS/3600
set /a PLANNED_MINUTES=(PLANNED_SECONDS%%3600)/60
set /a PLANNED_REMAIN_SECONDS=PLANNED_SECONDS%%60

echo ============================================================
echo Ping sweep 10.255.0.0/16 with ARP MAC lookup
echo Range: 10.255.0.1 - 10.255.255.254
echo Ping count: %PING_COUNT%
echo Timeout ms: %TIMEOUT_MS%
echo Total ping addresses: %TOTAL%
echo Planned time approx: %PLANNED_HOURS% h %PLANNED_MINUTES% min %PLANNED_REMAIN_SECONDS% sec
echo Output file: %OUT_FILE%
echo ============================================================
echo.

echo Ping sweep 10.255.0.0/16 with ARP MAC lookup > "%OUT_FILE%"
echo Range: 10.255.0.1 - 10.255.255.254 >> "%OUT_FILE%"
echo Ping count: %PING_COUNT% >> "%OUT_FILE%"
echo Timeout ms: %TIMEOUT_MS% >> "%OUT_FILE%"
echo Total ping addresses: %TOTAL% >> "%OUT_FILE%"
echo Planned time approx: %PLANNED_HOURS% h %PLANNED_MINUTES% min %PLANNED_REMAIN_SECONDS% sec >> "%OUT_FILE%"
echo Started: %DATE% %TIME% >> "%OUT_FILE%"
echo. >> "%OUT_FILE%"
echo IP;MAC >> "%OUT_FILE%"

REM ============================================================
REM First block:
REM   10.255.0.1 - 10.255.0.255
REM ============================================================

for /L %%D in (1,1,255) do (
    set /a CURRENT+=1
    set "CURRENT_IP=%NET_A%.%NET_B%.0.%%D"

    call :PingAndSave
    call :ShowProgress
)

REM ============================================================
REM Middle blocks:
REM   10.255.1.0 - 10.255.254.255
REM
REM In a real /16 network, .0 and .255 inside middle /24 blocks
REM are valid host addresses. Therefore they are included.
REM ============================================================

for /L %%C in (1,1,254) do (
    echo Scanning 10.255.%%C.0/24 ...

    for /L %%D in (0,1,255) do (
        set /a CURRENT+=1
        set "CURRENT_IP=%NET_A%.%NET_B%.%%C.%%D"

        call :PingAndSave
        call :ShowProgress
    )
)

REM ============================================================
REM Last block:
REM   10.255.255.0 - 10.255.255.254
REM ============================================================

echo Scanning 10.255.255.0/24 ...

for /L %%D in (0,1,254) do (
    set /a CURRENT+=1
    set "CURRENT_IP=%NET_A%.%NET_B%.255.%%D"

    call :PingAndSave
    call :ShowProgress
)

echo. >> "%OUT_FILE%"
echo Finished: %DATE% %TIME% >> "%OUT_FILE%"
echo Alive hosts: %ALIVE_COUNT% >> "%OUT_FILE%"

echo.
echo ============================================================
echo Done.
echo Alive hosts: %ALIVE_COUNT%
echo Results saved to:
echo %OUT_FILE%
echo ============================================================
echo.

pause
exit /b


:PingAndSave
REM ============================================================
REM Pings CURRENT_IP.
REM If alive, reads MAC from ARP table and writes IP;MAC to file.
REM ============================================================

ping -n %PING_COUNT% -w %TIMEOUT_MS% !CURRENT_IP! | find "TTL=" >nul

if not errorlevel 1 (
    set /a ALIVE_COUNT+=1

    call :GetMacAddress !CURRENT_IP!

    echo !CURRENT_IP!;!CURRENT_MAC! >> "%OUT_FILE%"
    echo Alive: !CURRENT_IP!  MAC: !CURRENT_MAC!
)

exit /b


:GetMacAddress
REM ============================================================
REM Reads Windows ARP table and finds MAC address for given IP.
REM Input:
REM   %1 = IP address
REM Output:
REM   CURRENT_MAC variable
REM ============================================================

set "SEARCH_IP=%~1"
set "CURRENT_MAC=UNKNOWN"

for /f "tokens=1,2,3" %%A in ('arp -a') do (
    if "%%A"=="!SEARCH_IP!" (
        set "CURRENT_MAC=%%B"
    )
)

exit /b


:ShowProgress
REM ============================================================
REM Shows progress bar.
REM ============================================================

set /a PERCENT=CURRENT*100/TOTAL
set /a FILLED=PERCENT*BAR_WIDTH/100
set /a EMPTY=BAR_WIDTH-FILLED

set "BAR="

for /L %%B in (1,1,!FILLED!) do (
    set "BAR=!BAR!#"
)

for /L %%B in (1,1,!EMPTY!) do (
    set "BAR=!BAR!-"
)

set /a MOD=CURRENT%%PRINT_EVERY

if "!MOD!"=="0" (
    echo [!BAR!] !PERCENT!%%  !CURRENT!/!TOTAL!  Alive: !ALIVE_COUNT!
)

if "!CURRENT!"=="!TOTAL!" (
    echo [!BAR!] !PERCENT!%%  !CURRENT!/!TOTAL!  Alive: !ALIVE_COUNT!
)

exit /b