【bat】ネットワーク接続の有無を判定して処理を分岐する方法|ping・ポート確認・リトライループ・落とし穴まで完全解説

【bat】バッチファイルでネットワーク接続の有無を判定して処理を分岐させる方法 bat

バッチファイルで「ネットワークにつながっているか」を判定してオンライン・オフラインで処理を切り替えたい場面はよくあります。本記事では ping の基本から findstr による精密判定、複数ホストのチェック、リトライループ、ポート疎通確認、よくある落とし穴まで体系的に解説します。

この記事で解決できること

  • ping の ERRORLEVEL でネットワーク接続を判定する基本パターン
  • ping がブロックされる環境での代替判定方法
  • findstr で ping 結果を文字列で精密に判定する方法
  • 特定ポートの疎通確認(telnet / PowerShell)
  • 複数ホストを順番にチェックして1つでも応答があれば続行する方法
  • リトライ付き待機ループで接続回復を待つ方法
スポンサーリンク

判定方法の選び方

ネットワーク接続の確認方法は目的によって使い分けます。

確認したいこと 推奨方法
インターネット接続の有無 ping 8.8.8.8 または 1.1.1.1
社内サーバーへの到達確認 ping サーバーIP・ホスト名
特定サービスのポート確認 PowerShell Test-NetConnection / telnet
ネットワークドライブのマウント確認 if exist でパスを確認
ping がブロックされる環境 curl / PowerShell Invoke-WebRequest

基本パターン:ping の ERRORLEVEL で分岐

最もシンプルな判定

@echo off

REM ping を1回だけ送り、結果を画面に出さない
ping -n 1 8.8.8.8 >nul 2>&1

if errorlevel 1 (
    echo [オフライン] ネットワークに接続されていません。
) else (
    echo [オンライン] ネットワークに接続されています。
)
ping の終了コードとは
ping コマンドは応答があれば終了コード 0、タイムアウト・到達不能なら 1 を返します。if errorlevel 1 は「終了コードが 1 以上」という意味なので、接続失敗を正しく検出できます。

タイムアウトを短く設定する(高速判定)

@echo off

REM -n 1: 1回送信 / -w 1000: タイムアウトを1000ミリ秒(1秒)に短縮
ping -n 1 -w 1000 8.8.8.8 >nul 2>&1

if errorlevel 1 (
    echo ネットワーク接続なし
) else (
    echo ネットワーク接続あり
)
デフォルトのタイムアウトは4秒
-w オプションを省略すると、ping は1回あたり最大4秒待ちます。スクリプトをすばやく動かしたい場合は -w 1000(1秒)などに短縮してください。

精密判定:findstr で ping 結果の文字列を解析する

ERRORLEVEL では「ホストが存在しない」と「パケットロス 100%」を区別できません。findstr で出力文字列を調べると、より正確な判定ができます。

@echo off
setlocal

REM ping 結果を一時変数に取り込んで解析する
set ONLINE=0
for /f "delims=" %%L in ('ping -n 1 8.8.8.8') do (
    echo %%L | findstr /i "TTL=" >nul
    if not errorlevel 1 set ONLINE=1
)

if "%ONLINE%"=="1" (
    echo [オンライン] TTL 応答あり
) else (
    echo [オフライン] TTL 応答なし
)
endlocal
TTL= が含まれていれば確実に応答あり
ping の応答行には必ず TTL=(Time To Live)の文字列が含まれます。これで判定すると「要求がタイムアウトしました」「宛先ホストに到達できません」を確実に除外できます。ERRORLEVEL だけでは区別できないケースをカバーできる精密な方法です。

社内サーバーへの接続確認

@echo off

REM 社内サーバーのIPまたはホスト名で確認
set SERVER=192.168.1.10

ping -n 1 -w 2000 %SERVER% >nul 2>&1

if errorlevel 1 (
    echo [ERROR] サーバー %SERVER% に到達できません。
    echo 処理を中断します。
    exit /b 1
) else (
    echo [OK] サーバー %SERVER% に接続確認できました。
    echo 処理を開始します。
)

複数ホストを順番にチェックする

1つのサーバーがメンテナンス中でも別のサーバーで続行したい場合、複数ホストを順番に試します。

@echo off
setlocal

REM チェックするホストを順番に定義
set HOSTS=192.168.1.10 192.168.1.11 192.168.1.12
set CONNECTED_HOST=

for %%H in (%HOSTS%) do (
    ping -n 1 -w 1000 %%H >nul 2>&1
    if not errorlevel 1 (
        set CONNECTED_HOST=%%H
        goto :found
    )
    echo %%H: 応答なし
)

echo [ERROR] すべてのホストに接続できませんでした。
exit /b 1

:found
echo [OK] %CONNECTED_HOST% に接続しました。処理を開始します。
endlocal

リトライ付き待機ループ

ネットワークが一時的に切れた場合に接続回復を待ってから処理を再開するパターンです。

@echo off
setlocal enabledelayedexpansion

set TARGET=8.8.8.8
set RETRY_MAX=10
set INTERVAL=5
set /a RETRY=0

:retry_loop
ping -n 1 -w 2000 %TARGET% >nul 2>&1
if not errorlevel 1 goto :connected

set /a RETRY+=1
if !RETRY! GEQ !RETRY_MAX! (
    echo [ERROR] %RETRY_MAX% 回試みましたが接続できませんでした。
    exit /b 1
)

echo 接続待機中... (!RETRY!/%RETRY_MAX%) %INTERVAL% 秒後に再試行します
timeout /t %INTERVAL% /nobreak >nul
goto :retry_loop

:connected
echo [OK] ネットワーク接続を確認しました。
endlocal

特定ポートの疎通確認

ping が通っても特定のサービスポートが開いているかどうかは別問題です。ポートレベルの確認には PowerShell を使うのが最も確実です。

PowerShell の Test-NetConnection でポート確認

@echo off

REM PowerShell の Test-NetConnection でポート 1521(Oracle)を確認
powershell -NoProfile -Command "if ((Test-NetConnection -ComputerName 192.168.1.10 -Port 1521 -InformationLevel Quiet) -eq $true) { exit 0 } else { exit 1 }"

if errorlevel 1 (
    echo [ERROR] ポート 1521 に接続できません。
    exit /b 1
) else (
    echo [OK] ポート 1521 が開いています。
)

REM ポート番号を変えれば他のサービスも確認できる
REM  80   : HTTP
REM  443  : HTTPS
REM  3389 : RDP
REM  1521 : Oracle DB
REM  3306 : MySQL
REM  5432 : PostgreSQL

telnet でポート確認(古い環境向け)

@echo off

REM telnet でポート確認(telnet クライアントが有効な場合)
echo. | telnet 192.168.1.10 80 >nul 2>&1

if errorlevel 1 (
    echo [ERROR] ポート 80 に接続できません。
) else (
    echo [OK] ポート 80 が開いています。
)
telnet クライアントはデフォルト無効
Windows Server 2008 以降・Windows Vista 以降では telnet クライアントはデフォルトで無効です。有効化するには「コントロールパネル → プログラムと機能 → Windows の機能の有効化または無効化 → Telnet クライアント」で有効にする必要があります。本番環境では PowerShell の Test-NetConnection を使う方が確実です。

ping がブロックされる環境での代替判定

ファイアウォールで ICMP(ping)が遮断されている環境では、curl や PowerShell で HTTP 疎通を確認します。

@echo off

REM PowerShell で HTTP 接続を確認(ICMP ブロック環境)
powershell -NoProfile -Command "try { $r=(New-Object Net.WebClient).DownloadString('http://www.gstatic.com/generate_204'); exit 0 } catch { exit 1 }"

if errorlevel 1 (
    echo [オフライン] HTTP 接続できません。
) else (
    echo [オンライン] HTTP 接続できます。
)

REM curl が使える環境(Windows 10 1803 以降に標準搭載)
curl -s -o nul -w "%%{http_code}" --max-time 3 http://www.gstatic.com/generate_204 >nul 2>&1
if errorlevel 1 (
    echo [オフライン]
) else (
    echo [オンライン]
)

ネットワークドライブの存在確認

@echo off

REM ネットワークドライブ Z: のマウント確認
if exist Z:\ (
    echo [OK] Z ドライブが利用可能です。
) else (
    echo [ERROR] Z ドライブが見つかりません。
)

REM UNC パスで直接確認
if exist \\192.168.1.10\share\ (
    echo [OK] 共有フォルダに接続できます。
) else (
    echo [ERROR] 共有フォルダに接続できません。
)

実践サンプル:接続確認→ログ出力→ファイル転送

@echo off
setlocal enabledelayedexpansion

set LOGFILE=%~dp0sync_%DATE:/=%.log
set SERVER=192.168.1.10
set SRC=C:\data\export
set DST=\\%SERVER%\backup\export

call :log "同期処理開始"

REM ネットワーク確認
ping -n 1 -w 2000 %SERVER% >nul 2>&1
if errorlevel 1 (
    call :log "[ERROR] サーバー %SERVER% に接続できません。処理スキップ。"
    exit /b 1
)
call :log "[OK] サーバー接続確認"

REM ファイル転送(ROBOCOPY)
robocopy "%SRC%" "%DST%" /MIR /LOG+:"%LOGFILE%" /NP /NFL
if errorlevel 8 (
    call :log "[ERROR] ROBOCOPY でエラーが発生しました。ERRORLEVEL=!errorlevel!"
    exit /b 1
)
call :log "[OK] 同期完了"
exit /b 0

:log
echo [%DATE% %TIME%] %~1
echo [%DATE% %TIME%] %~1 >> "%LOGFILE%"
exit /b 0

ROBOCOPY のオプション詳細は ROBOCOPY の使い方完全ガイド(ミラーリング・差分コピー・ログ出力) で解説しています。ログ出力の自動管理については バッチファイルのログローテーション実装ガイド を参照してください。

よくある落とし穴と対処法

落とし穴1: ping はブロックされることがある

REM NG: 社内ファイアウォールが ICMP を遮断していると常にオフライン判定になる
ping -n 1 server01 >nul
if errorlevel 1 echo オフライン  ← ping ブロック環境では誤判定

REM OK: ポート確認や HTTP 確認で代替する
powershell -NoProfile -Command "if ((Test-NetConnection -ComputerName server01 -Port 445 -InformationLevel Quiet) -eq $true) { exit 0 } else { exit 1 }"

落とし穴2: 名前解決の失敗と通信失敗を区別したい

REM 名前解決に失敗した場合も ping の ERRORLEVEL は 1 になる
ping -n 1 nonexistent.example.com >nul 2>&1

REM 区別したい場合は findstr で出力メッセージを解析する
set PING_OK=0
set DNS_FAIL=0

for /f "delims=" %%L in ('ping -n 1 server01') do (
    echo %%L | findstr /i "TTL=" >nul
    if not errorlevel 1 set PING_OK=1
    echo %%L | findstr /i "ping request could not find host" >nul
    if not errorlevel 1 set DNS_FAIL=1
)

if "%PING_OK%"=="1" (
    echo [OK] 接続成功
) else if "%DNS_FAIL%"=="1" (
    echo [ERROR] DNS 名前解決に失敗しました
) else (
    echo [ERROR] ホストに到達できません
)

落とし穴3: 2>&1 を忘れてエラーメッセージが画面に出る

REM NG: 標準出力だけ抑制しても標準エラーが画面に出ることがある
ping -n 1 nonexistent.host >nul

REM OK: 標準エラーも /nul にリダイレクト
ping -n 1 nonexistent.host >nul 2>&1

落とし穴4: ERRORLEVEL の誤った使い方

REM NG: == 0 の比較では動かないケースがある(環境依存)
if %errorlevel%==0 echo 成功   ← 動くが not errorlevel 1 の方が確実

REM OK: not errorlevel 1 で「0の場合」を表現する(バッチの正式な書き方)
if not errorlevel 1 echo 成功

REM OK: if errorlevel 1 で「1以上の場合(失敗)」
if errorlevel 1 echo 失敗

よくある質問(FAQ)

Q ping の宛先に何を指定すればよいですか?
A

目的に合わせて使い分けてください。

確認したいこと 推奨する宛先
インターネット接続 8.8.8.8(Google DNS)/ 1.1.1.1(Cloudflare)
社内ネットワーク接続 社内のファイルサーバーや DC の IP
特定サーバーへの接続 対象サーバーのIPまたはホスト名

インターネット確認に www.google.com などドメイン名を使うと DNS 障害時に誤判定することがあります。IP アドレスを使う方が確実です。

Q ping のタイムアウトを最小にするには?
A

-w オプションで 1 ミリ秒単位で指定できます。ただし、あまり短くすると LAN 内でも失敗することがあります。

REM タイムアウトを 500ms に設定(LAN 内で十分な速さ)
ping -n 1 -w 500 192.168.1.10 >nul 2>&1

REM インターネット向けは 2〜3 秒が安定
ping -n 1 -w 2000 8.8.8.8 >nul 2>&1
Q ping の回数を増やして信頼性を上げたい
A

複数回送って1回でも成功すれば OK とする場合は findstr 判定が使いやすいです。

@echo off
setlocal
set ONLINE=0

REM 3回送って1回でも TTL= が返れば接続あり
for /f "delims=" %%L in ('ping -n 3 -w 1000 8.8.8.8') do (
    echo %%L | findstr /i "TTL=" >nul
    if not errorlevel 1 set ONLINE=1
)

if "%ONLINE%"=="1" (
    echo [OK] 応答あり(3回中1回以上)
) else (
    echo [ERROR] すべてタイムアウト
)
endlocal
Q 接続確認の結果をログファイルに残したい
A

ログ出力サブルーチンを作っておくと管理しやすくなります。

@echo off
setlocal
set LOGFILE=%~dp0network_check.log

ping -n 1 -w 2000 8.8.8.8 >nul 2>&1
if errorlevel 1 (
    call :log "OFFLINE" "8.8.8.8 に到達できません"
) else (
    call :log "ONLINE" "8.8.8.8 接続確認OK"
)
exit /b 0

:log
echo [%DATE% %TIME%] [%~1] %~2
echo [%DATE% %TIME%] [%~1] %~2 >> "%LOGFILE%"
exit /b 0
Q 接続確認の結果を別バッチに戻り値として渡したい
A

exit /b 0(接続あり)/ exit /b 1(接続なし)で戻り値を返し、呼び出し元で if errorlevel を使って分岐できます。詳細は EXIT /B 完全解説(戻り値・ウィンドウを閉じない仕組み) を参照してください。

REM check_network.bat
@echo off
ping -n 1 -w 2000 8.8.8.8 >nul 2>&1
if errorlevel 1 (exit /b 1) else (exit /b 0)

REM main.bat から呼び出す側
call check_network.bat
if errorlevel 1 (
    echo オフライン - 処理スキップ
) else (
    echo オンライン - 処理実行
)

まとめ

判定方法 コマンド 特徴
ping ERRORLEVEL ping -n 1 -w 1000 HOST >nul 2>&1 シンプル・標準的
ping + findstr TTL= for /f ... | findstr "TTL=" 精密・タイムアウトと区別可
ポート確認 powershell Test-NetConnection -Port N サービス疎通まで確認
HTTP 確認 powershell Invoke-WebRequest ICMP ブロック環境向け
ネットワークドライブ if exist Z:\ マウント状態の確認
UNC パス if exist \\server\share\ 共有フォルダの存在確認

ネットワーク確認後のファイル転送には ROBOCOPY の使い方完全ガイド(ミラーリング・差分コピー・ログ出力)、判定結果の返し方の詳細は EXIT /B 完全解説(戻り値・ウィンドウを閉じない仕組み)、ループ内での変数管理は setlocal enabledelayedexpansion 完全ガイド(FOR内変数・遅延展開) を参照してください。