Skip to main content

How to Capture Network Traffic Statistics with NETSTAT in Batch Script

Monitoring basic network traffic statistics can be incredibly helpful when diagnosing sudden spikes in latency, verifying if a server is successfully transmitting data, or checking for dropped packets. While tools like Wireshark provide deep packet inspection, the built-in netstat (Network Statistics) command offers a quick, scriptable way to gather high-level traffic metrics.

In this guide, we will explore how to use netstat in a Batch script to capture overall network interface statistics and protocol-specific data.

The netstat -e and netstat -s Commands

The netstat utility has two primary switches for gathering statistical data rather than just listing active connections:

  • -e (Ethernet Statistics): Displays broad interface statistics, such as total bytes sent/received, errors, and discarded packets.
  • -s (Protocol Statistics): Displays granular statistics organized by protocol (IPv4, IPv6, ICMP, TCP, UDP).

Capturing Ethernet Statistics (netstat -e)

When you run netstat -e, the output looks like this:

Interface Statistics

Received Sent

Bytes 1234567890 987654321
Unicast packets 1234567 987654
Non-unicast packets 12345 9876
Discards 0 0
Errors 0 0
Unknown protocols 0

Script to Capture Bytes Transmitted

This script extracts the total sent and received bytes with proper validation.

@echo off
setlocal enabledelayedexpansion

echo [STATS] Capturing Ethernet Traffic Statistics...
echo.

set "BytesReceived="
set "BytesSent="

:: Parse the "Bytes" line from netstat -e
:: Format: " Bytes <Received> <Sent>"
for /f "tokens=1,2,3" %%A in ('netstat -e ^| findstr /c:"Bytes"') do (
:: %%A = "Bytes" (label)
:: %%B = Received value
:: %%C = Sent value
if /i "%%A"=="Bytes" (
set "BytesReceived=%%B"
set "BytesSent=%%C"
)
)

:: Validate results
if not defined BytesReceived (
echo [ERROR] Could not parse netstat -e output.
pause
endlocal
exit /b 1
)

echo ========================================
echo Bytes Received: !BytesReceived!
echo Bytes Sent: !BytesSent!
echo ========================================

:: Convert to human-readable format using PowerShell (avoids 32-bit overflow)
powershell -NoProfile -Command ^
"$rec = [int64]'%BytesReceived%'; $sent = [int64]'%BytesSent%';"^
"$units = @('Bytes','KB','MB','GB','TB');"^
"function ConvertSize($b) { $i=0; $v=[double]$b; while ($v -ge 1024 -and $i -lt 4) { $v /= 1024; $i++ }; '{0:N2} {1}' -f $v,$units[$i] };"^
"Write-Host '';"^
"Write-Host (' Received: ' + (ConvertSize $rec));"^
"Write-Host (' Sent: ' + (ConvertSize $sent));"^
"Write-Host (' Total: ' + (ConvertSize ($rec + $sent)))"

echo.
pause
endlocal
Why use PowerShell for the conversion?

Raw byte counts like 1234567890 are hard to read.

  • PowerShell converts them to human-readable units (KB, MB, GB) and handles 64-bit integers safely.
  • Batch's set /a overflows at 2,147,483,647 bytes (~2 GB), which a Gigabit interface can exceed in seconds.

Capturing Protocol Statistics (netstat -s)

The -s switch dumps detailed data about connection failures, segments retransmitted, and datagrams received.

To capture this to a file for review over time (e.g., creating a baseline of how many TCP connection failures occur daily), redirect the output to a timestamped file.

@echo off
setlocal

:: Create log directory
set "LogDir=%USERPROFILE%\NetworkLogs"
if not exist "%LogDir%" mkdir "%LogDir%"

:: Generate timestamp for filename using wmic (reliable format)
set "DateStamp="
for /f "tokens=2 delims==" %%d in ('wmic os get localdatetime /value 2^>nul') do (
for /f "delims=" %%e in ("%%d") do set "DateStamp=%%e"
)

if defined DateStamp (
set "FileDate=!DateStamp:~0,8!"
) else (
:: Fallback if wmic fails
set "FileDate=unknown"
)

set "LogFile=%LogDir%\NetworkStats_%FileDate%.txt"

echo [LOG] Saving full protocol statistics...
echo File: %LogFile%
echo.

(
echo ========================================
echo Network Protocol Statistics
echo Captured: %date% %time%
echo Computer: %COMPUTERNAME%
echo ========================================
echo.
netstat -s
) > "%LogFile%"

echo [OK] Statistics saved successfully.
echo.

:: Quick summary: extract key TCP metrics
echo --- TCP Quick Summary ---
findstr /i /c:"Active Opens" /c:"Passive Opens" /c:"Failed" /c:"Reset" /c:"Segments Retransmitted" "%LogFile%"
echo.

pause
endlocal
Why extract key TCP metrics?

The full netstat -s output is hundreds of lines long. Pulling out "Active Opens," "Failed Connections," and "Segments Retransmitted" gives you an instant health check without reading the entire file.

Creating a Traffic Delta Monitor

A common task is measuring network traffic over a period of time (a delta). By capturing netstat -e at Time A, waiting, and capturing again at Time B, you can calculate the bandwidth used during that interval.

The Problem with Batch Math

Batch's set /a can only handle 32-bit signed integers (maximum 2,147,483,647, roughly 2 GB). Modern Gigabit interfaces exceed this threshold within seconds of normal use, causing arithmetic overflow errors or negative numbers.

:: WRONG - Will break when byte counts exceed ~2 GB
set /a "DeltaSent=%CurrentSent% - %PreviousSent%"

The Solution: Using PowerShell for 64-Bit Math

This script measures bytes sent and received over a configurable interval with proper 64-bit arithmetic.

@echo off
setlocal

set "Interval=5"

echo [MONITOR] Measuring network traffic over %Interval% seconds...
echo Please wait...
echo.

powershell -NoProfile -Command "param([int]$Interval=%Interval%); $stats1=(netstat -e | Select-String 'Bytes'); $nums1=($stats1 | Select-Object -Last 1).Line -split '\s+' | Where-Object { $_ -match '^\d+$' }; $rec1=[int64]$nums1[0]; $sent1=[int64]$nums1[1]; Write-Host (' Sample 1 captured. Waiting '+$Interval+' seconds...'); Start-Sleep -Seconds $Interval; $stats2=(netstat -e | Select-String 'Bytes'); $nums2=($stats2 | Select-Object -Last 1).Line -split '\s+' | Where-Object { $_ -match '^\d+$' }; $rec2=[int64]$nums2[0]; $sent2=[int64]$nums2[1]; $diffRec=$rec2-$rec1; $diffSent=$sent2-$sent1; $totalDiff=$diffRec+$diffSent; function ConvertSize($b){$units=@('Bytes','KB','MB','GB');$i=0;$v=[double]$b;while($v -ge 1024 -and $i -lt 3){$v = $v / 1024; $i++}; '{0:N2} {1}' -f $v,$units[$i]}; $recRate=ConvertSize([math]::Round($diffRec/$Interval)); $sentRate=ConvertSize([math]::Round($diffSent/$Interval)); Write-Host ''; Write-Host ' ============================================'; Write-Host (' Traffic over {0} seconds:' -f $Interval); Write-Host ' ============================================'; Write-Host (' Received: ' + (ConvertSize $diffRec) + ' (' + $recRate + '/sec)'); Write-Host (' Sent: ' + (ConvertSize $diffSent) + ' (' + $sentRate + '/sec)'); Write-Host (' Total: ' + (ConvertSize $totalDiff)); Write-Host ' ============================================'"

echo.
pause
endlocal

Capturing Dropped Packets and Errors

Administrators use network statistics to detect hardware problems like a bad network cable causing dropped packets. This script checks for interface errors and provides actionable severity assessment.

@echo off
setlocal enabledelayedexpansion

echo [HEALTH] Checking network interface for errors...
echo.

set "WarningCount=0"
set "TempFile=%TEMP%\netstat_e.tmp"

:: Capture netstat -e output once
netstat -e > "%TempFile%" 2>&1

echo TYPE RECEIVED SENT
echo =============================================

:: Parse Discards and Errors lines
for /f "tokens=1,2,3" %%A in ('findstr /i "Discards Errors" "%TempFile%"') do (
set "label=%%A"
set "recv=%%B"
set "sent=%%C"

echo !label! !recv! !sent!

:: Alert if any values are greater than 0
:: Need to handle non-numeric values gracefully
set "recvNum=%%B"
set "sentNum=%%C"

if defined recvNum if "!recvNum!" neq "" (
if !recvNum! gtr 0 (
echo [WARNING] !recvNum! received !label! detected
set /a WarningCount+=1
)
)
if defined sentNum if "!sentNum!" neq "" (
if !sentNum! gtr 0 (
echo [WARNING] !sentNum! sent !label! detected
set /a WarningCount+=1
)
)
)

echo =============================================
echo.

:: Also check for Unknown Protocols
for /f "tokens=1,2,3" %%A in ('findstr /i "Unknown" "%TempFile%"') do (
echo [INFO] Unknown protocols: %%C
echo This is usually normal - broadcast traffic from non-IP protocols.
)

echo.

if !WarningCount! equ 0 (
echo [OK] No interface errors or discards detected.
) else (
echo [ALERT] !WarningCount! warnings found
echo Possible causes: damaged cable, bad switch port, or driver issues.
echo Monitor over time to see if errors are increasing.
)

:: Clean up
del "%TempFile%" >nul 2>&1

pause
endlocal

About "Unknown Protocols": Don't panic if netstat -e shows a high number under "Unknown protocols." On modern networks, machines receive broadcast traffic for protocols (like older discovery protocols or non-IP traffic) that the TCP/IP stack ignores, logging them as "Unknown." This is normal behavior.

Continuous Statistics Logger

For long-term monitoring, log key metrics at regular intervals with timestamps.

@echo off
setlocal enabledelayedexpansion

set "LogFile=%USERPROFILE%\netstats_continuous.csv"
set "Interval=60"
set "MaxSamples=1440"

echo [MONITOR] Continuous network statistics logger
echo Log: %LogFile%
echo Interval: %Interval% seconds
echo Samples: %MaxSamples% approximately 24 hours at 60s intervals
echo Press CTRL+C to stop.
echo.

:: CSV header
if not exist "%LogFile%" (
echo Date,Time,BytesReceived,BytesSent,Discards_Recv,Discards_Sent,Errors_Recv,Errors_Sent >> "%LogFile%"
)

set "SampleCount=0"

:Loop
set /a SampleCount+=1
if !SampleCount! gtr %MaxSamples% (
echo [DONE] Reached maximum sample count.
goto :End
)

:: Capture all metrics from netstat -e
set "bRecv=" & set "bSent="
set "dRecv=" & set "dSent="
set "eRecv=" & set "eSent="

for /f "tokens=1,2,3" %%A in ('netstat -e ^| findstr /i "Bytes Discards Errors"') do (
if /i "%%A"=="Bytes" ( set "bRecv=%%B" & set "bSent=%%C" )
if /i "%%A"=="Discards" ( set "dRecv=%%B" & set "dSent=%%C" )
if /i "%%A"=="Errors" ( set "eRecv=%%B" & set "eSent=%%C" )
)

:: Log to CSV
echo !date!,!time!,!bRecv!,!bSent!,!dRecv!,!dSent!,!eRecv!,!eSent! >> "%LogFile%"

:: Brief screen output
echo [!time!] Sample !SampleCount! - Recv: !bRecv! Sent: !bSent! Errors: !eRecv!/!eSent!

timeout /t %Interval% >nul
goto :Loop

:End
echo [DONE] Log saved to: %LogFile%
pause
endlocal

How to Avoid Common Errors

Wrong Way: Using set /a for Byte Count Arithmetic

Batch's set /a overflows at 2,147,483,647 (~2 GB). A Gigabit interface can transfer this amount in under 20 seconds. Any subtraction or addition on larger values will produce negative numbers or "Invalid number" errors.

Correct Way: Delegate all byte-count arithmetic to PowerShell, which uses 64-bit integers natively:

powershell -NoProfile -Command "[int64]$sent2 - [int64]$sent1"

Wrong Way: Using %DATE% in Filenames Directly

The %DATE% variable format varies by locale and regional settings. On one machine it might be Mon 01/15/2025, on another 2025-01-15. This creates unpredictable filenames and breaks file management.

Correct Way: Use WMIC to get a standardized date string:

for /f "tokens=2 delims==" %%d in ('wmic os get localdatetime /value') do (
for /f "delims=" %%e in ("%%d") do set "DateStamp=%%e"
)
set "FileDate=%DateStamp:~0,8%"

Wrong Way: No Validation After Parsing

If netstat -e output format changes or the command fails, your variables will be empty. Using them in calculations or displays produces confusing output.

Correct Way: Always validate parsed values before using them:

if not defined BytesReceived (
echo [ERROR] Could not parse netstat output.
exit /b 1
)

Problem: Locale-Dependent Output

The labels in netstat -e (like "Bytes," "Discards," "Errors") may be translated in non-English Windows versions.

Solution: For international deployment, use PowerShell's Get-NetAdapterStatistics which returns structured objects with language-independent property names:

Get-NetAdapterStatistics | Select-Object Name, ReceivedBytes, SentBytes

Best Practices and Rules

1. Baseline First

Before looking for problems, capture a "normal" baseline during low-traffic hours. Without knowing what's normal, you can't identify what's abnormal.

2. Monitor Errors Over Time, Not Just Once

A single snapshot showing "0 Errors" doesn't mean the interface is healthy, the counter may have been recently reset. Log errors continuously (using the Continuous Statistics Logger) and watch for the count increasing over time.

3. Use CSV for Long-Term Data

Format logs as CSV so you can import them into Excel or a monitoring dashboard. This allows you to create charts showing traffic patterns, error trends, and peak usage times.

4. Log File Location

Avoid hardcoding paths like C:\Logs\, the directory may not exist and the script will fail silently. Use %USERPROFILE% or create the directory first with if not exist:

set "LogDir=%USERPROFILE%\NetworkLogs"
if not exist "%LogDir%" mkdir "%LogDir%"

5. Always Use setlocal / endlocal

Without setlocal, every variable your script creates persists in the parent shell session, causing potential conflicts when running multiple scripts in sequence.

Summary

The netstat -e and netstat -s commands are powerful, built-in tools for gathering network metrics. By writing Batch scripts to parse this data, you can quickly monitor overall bandwidth usage, check for network interface errors, or log protocol stats over time. Always use PowerShell for byte-count arithmetic to avoid Batch's 32-bit integer overflow, and validate your parsed output to ensure reliable results across different Windows versions and locales.