【bat】バッチファイルでWebサイトからファイルをダウンロードする方法完全ガイド|curl・PowerShell・リトライ・認証・実践パターンまで

【bat】バッチファイルでWebサイトからファイルをダウンロードする方法完全ガイド|curl・PowerShell・リトライ・認証・実践パターンまで bat

バッチファイルでWebサイトからファイルを自動ダウンロードするには、主に curl(Windows 10以降標準搭載)と PowerShell の2つの方法があります。

この記事では ダウンロードの全パターン を体系的に解説します。基本的な1ファイルDLから「複数ファイルを一括DL」「リトライ付きで安定DL」「認証・プロキシ越し」「ダウンロード後にZIP解凍」といった実務パターンまで網羅します。

この記事でわかること

  • curl コマンドの基本(Windows 10/11 標準搭載・追加インストール不要)
  • curl の主要オプション(-o/-L/-f/-C-/–retry/–connect-timeout 等)
  • ダウンロード失敗を確実に検知してエラーハンドリングする方法
  • 複数URLをリストファイルから一括ダウンロードする方法
  • リトライ付きで安定してダウンロードする方法
  • PowerShell(Invoke-WebRequest/WebClient)との連携
  • HTTPS・Basic認証・プロキシへの対応
  • ダウンロード進捗のログ出力
  • 落とし穴5選・実践例3本・FAQ6問
スポンサーリンク
  1. 1. curl で最速ダウンロード(Windows 10以降 標準搭載)
  2. 2. curl オプション完全解説
  3. 3. エラーハンドリング(失敗検知と終了コード)
  4. 4. 複数URLをリストファイルから一括ダウンロード
  5. 5. リトライ付きで安定ダウンロード
    1. 5-1. curl –retry オプション(簡単・推奨)
    2. 5-2. カスタムリトライループ(進捗ログあり)
  6. 6. PowerShell との連携(UTF-8・大容量・高度なHTTP操作)
    1. 6-1. Invoke-WebRequest(基本)
    2. 6-2. WebClient(高速・大容量推奨)
  7. 7. 旧 Windows 環境(bitsadmin・certutil)
  8. 8. HTTPS・Basic認証・プロキシ対応
    1. 8-1. Basic認証付きダウンロード
    2. 8-2. プロキシ経由ダウンロード
    3. 8-3. SSL証明書エラーの対処(開発環境のみ)
  9. 9. ダウンロードログ・進捗出力
  10. 10. 落とし穴5選と対策
    1. 落とし穴1:-f なしだと HTTP エラーを検知できない
    2. 落とし穴2:URL のリダイレクトを追従しないと中身が空になる
    3. 落とし穴3:URLにスペースや特殊文字が含まれると失敗する
    4. 落とし穴4:出力先ディレクトリが存在しないと失敗する
    5. 落とし穴5:curl の exit code を即座に変数に保存しないと上書きされる
  11. 11. 実践例3本
    1. 実践例1:毎日ソフトウェアのアップデートファイルを自動ダウンロードして更新
    2. 実践例2:APIのレスポンスをJSONで取得して処理結果を記録する
    3. 実践例3:複数サイトからファイルを一括DLしてネット接続確認付きで安全に実行
  12. 12. まとめ:ダウンロード方法の使い分け表
  13. FAQ

1. curl で最速ダウンロード(Windows 10以降 標準搭載)

Windows 10バージョン1803以降、curl は標準搭載されているため追加インストール不要です。最もシンプルな1ファイルダウンロードは以下のとおりです。

@echo off
set "URL=https://example.com/data.zip"
set "OUTFILE=C:\work\data.zip"

:: -o: 出力ファイル名を指定 / -L: リダイレクト追従
curl -L -o "%OUTFILE%" "%URL%"

:: ERRORLEVEL が 0 なら成功
if %ERRORLEVEL% neq 0 (
    echo [ERROR] ダウンロード失敗: %URL%
    exit /b 1
)
echo [OK] ダウンロード完了: %OUTFILE%

-L オプションはリダイレクト(302等)を自動で追従します。CDN や短縮URLからのダウンロードでは必須です。

curl のバージョン確認

curl --version
:: curl 8.x が表示されれば OK
:: 「curl は、内部コマンドまたは外部コマンド〜」が出る場合は
:: Windows に付属の curl.exe が PATH に含まれていない(稀)

2. curl オプション完全解説

実務でよく使うオプションを体系的に解説します。

オプション 意味 用途
-o ファイル名 出力ファイル名を指定 ほぼ必須。パスも含めて指定可
-O URL末尾のファイル名で保存 ファイル名をそのまま使いたい場合
-L リダイレクト追従 CDN・短縮URL・GitHub Releases 等
-s 進捗・エラーを非表示 サイレントモード(ログ不要な場合)
-S エラーのみ表示(-s と併用) -sS で進捗消しつつエラーは表示
-f HTTPエラーで失敗扱い 404/500 等で exit code 22 を返す
-C - レジューム(途中再開) 大容量ファイルの中断再開
--retry N 失敗時にN回リトライ ネットワーク不安定な環境
--retry-delay N リトライ間隔(秒) –retry と組み合わせ
--connect-timeout N 接続タイムアウト(秒) 無応答サーバーへの待機上限設定
--max-time N トータルタイムアウト(秒) ダウンロード全体の時間上限
-# プログレスバー表示 -s の代わりに視覚的な進捗を表示
-u ユーザー:パス Basic認証 認証が必要なダウンロード
-x プロキシ:ポート プロキシ指定 社内ネットワーク環境
-A "エージェント" User-Agent指定 ブラウザ偽装が必要なサイト
@echo off
:: よく使うオプションの組み合わせ例

:: 基本(リダイレクト追従 + 失敗検知 + サイレント)
curl -L -f -sS -o "output.zip" "https://example.com/file.zip"

:: リトライあり + タイムアウトあり
curl -L -f -sS --retry 3 --retry-delay 5 --connect-timeout 30 --max-time 300 ^
     -o "output.zip" "https://example.com/file.zip"

:: レジューム(大容量ファイルの中断再開)
curl -L -C - -o "largefile.zip" "https://example.com/largefile.zip"

:: プログレスバー表示
curl -L -# -o "output.zip" "https://example.com/file.zip"

3. エラーハンドリング(失敗検知と終了コード)

curl の終了コードを正しく判定することが重要です。特に -f フラグが必須です。-f なしでは HTTP 404 や 500 でも curl は exit code 0(成功)を返します。

@echo off
setlocal

set "URL=https://example.com/data.zip"
set "OUT=C:\work\data.zip"

:: -f: HTTPエラー(4xx/5xx)で失敗扱い(exit code 22)
:: -sS: 進捗非表示・エラーは表示
curl -L -f -sS -o "%OUT%" "%URL%"
set "ERR=%ERRORLEVEL%"

if %ERR% equ 0 (
    echo [OK] ダウンロード完了: %OUT%
    goto :done
)

:: エラーコード別メッセージ
if %ERR% equ 6  echo [ERROR] ホストが見つかりません(DNS解決失敗)
if %ERR% equ 7  echo [ERROR] 接続できませんでした(ポート・ファイアウォール)
if %ERR% equ 22 echo [ERROR] HTTPエラー(404/403/500等)
if %ERR% equ 23 echo [ERROR] ファイルへの書き込み失敗(権限・ディスク容量)
if %ERR% equ 28 echo [ERROR] タイムアウト
if %ERR% equ 35 echo [ERROR] SSL/TLS接続エラー
echo [ERROR] curl exit code: %ERR%
exit /b %ERR%

:done
endlocal

curl の全エラーコードは curl --manual | find "exit" または公式ドキュメントで確認できます。ERRORLEVELを使ったエラーハンドリング完全ガイド も参照してください。

4. 複数URLをリストファイルから一括ダウンロード

ダウンロードするURLが複数ある場合、URLリストファイルと for /f を組み合わせることで一括処理できます。

:: urls.txt の内容例(1行1URL):
:: https://example.com/file1.zip
:: https://example.com/file2.zip
:: https://example.com/file3.zip
@echo off
setlocal enabledelayedexpansion

set "URL_LIST=urls.txt"
set "OUT_DIR=C:\work\downloads"
set "SUCCESS=0"
set "FAIL=0"

if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"

for /f "usebackq eol=# tokens=* delims=" %%U in ("%URL_LIST%") do (
    if not "%%U"=="" (
        :: URLからファイル名を取得(%%~nxU はパス最後の部分)
        for %%F in ("%%U") do set "FNAME=%%~nxF"
        echo ダウンロード中: !FNAME!

        curl -L -f -sS -o "%OUT_DIR%\!FNAME!" "%%U"
        if !ERRORLEVEL! equ 0 (
            set /a SUCCESS+=1
            echo  [OK] !FNAME!
        ) else (
            set /a FAIL+=1
            echo  [FAIL] !FNAME! (exit code: !ERRORLEVEL!)
        )
    )
)

echo ===== 完了: 成功 !SUCCESS! 件 / 失敗 !FAIL! 件 =====
if !FAIL! gtr 0 exit /b 1

eol=# により # で始まるコメント行を無視します。URLリストにコメントを書けるようになり、管理が楽になります。

setlocal enabledelayedexpansion 完全ガイド も参照してください。

5. リトライ付きで安定ダウンロード

ネットワークが不安定な環境や、サーバー側に一時的な問題がある場合、リトライロジックを組み込むことで安定性が上がります。

5-1. curl –retry オプション(簡単・推奨)

@echo off
set "URL=https://example.com/data.zip"
set "OUT=C:\work\data.zip"

:: --retry 5: 失敗時に最大5回リトライ
:: --retry-delay 10: リトライ間隔10秒
:: --retry-max-time 120: リトライ全体の上限120秒
:: --retry-connrefused: 接続拒否でもリトライ
curl -L -f -sS --retry 5 --retry-delay 10 --retry-max-time 120 ^
     --retry-connrefused --connect-timeout 30 ^
     -o "%OUT%" "%URL%"

if %ERRORLEVEL% neq 0 (
    echo [ERROR] 5回リトライしましたが失敗しました
    exit /b 1
)
echo [OK] ダウンロード完了

5-2. カスタムリトライループ(進捗ログあり)

@echo off
setlocal enabledelayedexpansion

set "URL=https://example.com/data.zip"
set "OUT=C:\work\data.zip"
set "MAX_RETRY=3"
set "RETRY_WAIT=30"
set "ATTEMPT=0"

:retry_loop
set /a ATTEMPT+=1
echo [試行 !ATTEMPT!/!MAX_RETRY!] %URL%

curl -L -f -sS --connect-timeout 30 --max-time 300 -o "%OUT%" "%URL%"
set "DL_ERR=%ERRORLEVEL%"

if %DL_ERR% equ 0 (
    echo [OK] ダウンロード成功(試行 !ATTEMPT! 回目)
    goto :done
)

echo [WARN] 失敗(exit code: %DL_ERR%)
if !ATTEMPT! lss !MAX_RETRY! (
    echo      %RETRY_WAIT% 秒後にリトライします...
    timeout /t %RETRY_WAIT% /nobreak >nul
    goto :retry_loop
)

echo [ERROR] %MAX_RETRY% 回試みましたが失敗しました
exit /b 1

:done
endlocal

タイムアウト・待機処理の詳細は 処理を一時停止する方法完全ガイド を参照してください。

6. PowerShell との連携(UTF-8・大容量・高度なHTTP操作)

curl で対応できない場面(UTF-8ファイル名保持・cookie付きリクエスト・複雑なHTTPヘッダー設定など)では PowerShell が有効です。

6-1. Invoke-WebRequest(基本)

@echo off
set "URL=https://example.com/data.zip"
set "OUT=C:\work\data.zip"

:: PowerShell の Invoke-WebRequest でダウンロード
powershell -NoProfile -Command "
    try {
        Invoke-WebRequest -Uri "%URL%" -OutFile "%OUT%" -UseBasicParsing
        Write-Host "[OK] ダウンロード完了: %OUT%"
    } catch {
        Write-Error "[ERROR] $_"
        exit 1
    }
"

if %ERRORLEVEL% neq 0 exit /b 1

6-2. WebClient(高速・大容量推奨)

@echo off
set "URL=https://example.com/largefile.zip"
set "OUT=C:\work\largefile.zip"

:: WebClient は Invoke-WebRequest より高速で大容量ファイルに向いている
powershell -NoProfile -Command "
    $wc = New-Object System.Net.WebClient
    $wc.Headers.Add("User-Agent", "Mozilla/5.0")
    try {
        $wc.DownloadFile("%URL%", "%OUT%")
        Write-Host "[OK] ダウンロード完了: %OUT%"
    } catch {
        Write-Error "[ERROR] $_"
        exit 1
    }
"

if %ERRORLEVEL% neq 0 exit /b 1

PowerShellをバッチファイルから呼び出す方法 も参照してください。

7. 旧 Windows 環境(bitsadmin・certutil)

Windows 7/8 など curl が搭載されていない旧環境では以下の方法が使えます。現在のプロジェクトでは基本的に curl か PowerShell を推奨します。

@echo off
set "URL=https://example.com/file.zip"
set "OUT=C:\work\file.zip"

:: bitsadmin(Windows Vista以降、バックグラウンドDL)
bitsadmin /transfer myJob /download /priority normal "%URL%" "%OUT%"
if %ERRORLEVEL% neq 0 echo [ERROR] bitsadmin 失敗

:: certutil(緊急手段・遅い)
:: certutil -urlcache -split -f "%URL%" "%OUT%"

:: PowerShell 2.0以降(.NET WebClient)
:: powershell -Command "(New-Object Net.WebClient).DownloadFile('%URL%', '%OUT%')"

8. HTTPS・Basic認証・プロキシ対応

8-1. Basic認証付きダウンロード

@echo off
set "URL=https://example.com/protected/file.zip"
set "OUT=C:\work\file.zip"
set "USER=myuser"
set "PASS=mypassword"

:: -u ユーザー名:パスワード
:: パスワードをコマンドライン引数に含めたくない場合は .netrc ファイルを使う
curl -L -f -sS -u "%USER%:%PASS%" -o "%OUT%" "%URL%"

if %ERRORLEVEL% neq 0 (
    echo [ERROR] 認証失敗またはダウンロードエラー
    exit /b 1
)
echo [OK] 完了

8-2. プロキシ経由ダウンロード

@echo off
set "URL=https://example.com/file.zip"
set "OUT=C:\work\file.zip"
set "PROXY=http://proxy.example.com:8080"

:: -x: プロキシ指定
curl -L -f -sS -x "%PROXY%" -o "%OUT%" "%URL%"

:: プロキシ認証がある場合
:: curl -L -f -sS -x "%PROXY%" -U proxyuser:proxypass -o "%OUT%" "%URL%"

:: 環境変数 HTTPS_PROXY / HTTP_PROXY を使う方法(curl が自動認識)
:: set HTTPS_PROXY=http://proxy.example.com:8080
:: curl -L -f -sS -o "%OUT%" "%URL%"

if %ERRORLEVEL% neq 0 exit /b 1
echo [OK] 完了

8-3. SSL証明書エラーの対処(開発環境のみ)

:: 本番環境では絶対に使用しない(セキュリティリスク)
:: -k/--insecure: SSL証明書の検証を無効化(自己署名証明書のテスト環境用)
curl -L -f -k -sS -o "%OUT%" "%URL%"

:: 正しい対応: CA証明書バンドルを指定する
:: curl -L -f --cacert "C:\certs\ca-bundle.crt" -sS -o "%OUT%" "%URL%"

9. ダウンロードログ・進捗出力

定期実行のバッチでは、ダウンロード結果をログファイルに残すことが重要です。

@echo off
setlocal enabledelayedexpansion

:: 日付付きログファイル
set "LOGDIR=C:\work\logs"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"

for /f "tokens=2 delims==." %%D in ('wmic os get LocalDateTime /value ^| findstr LocalDateTime') do set "DT=%%D"
set "LOGFILE=%LOGDIR%\download_%DT:~0,8%.log"

call :log "===== ダウンロード開始: %date% %time% ====="

set "URL=https://example.com/data.zip"
set "OUT=C:\work\data.zip"

call :log "DL開始: %URL%"
curl -L -f -sS -o "%OUT%" "%URL%"
set "ERR=%ERRORLEVEL%"

if %ERR% equ 0 (
    call :log "[OK] 完了: %OUT%"
) else (
    call :log "[ERROR] 失敗 (exit code: %ERR%)"
    exit /b %ERR%
)

call :log "===== 完了 ====="
goto :eof

:log
echo %~1
echo [%date% %time%] %~1 >> "%LOGFILE%"
goto :eof

ログファイルの日付付き管理については 日付と時間をファイル名に挿入する方法完全ガイド を参照してください。

10. 落とし穴5選と対策

落とし穴1:-f なしだと HTTP エラーを検知できない

:: NG: -f なしでは 404 でも exit code 0 を返す
curl -L -o "file.zip" "https://example.com/notfound.zip"
if %ERRORLEVEL% equ 0 echo 成功  :: ← 404でも「成功」と表示される

:: OK: -f を付けることで 4xx/5xx が exit code 22 になる
curl -L -f -o "file.zip" "https://example.com/notfound.zip"
if %ERRORLEVEL% neq 0 echo [ERROR] HTTPエラー(404等)

落とし穴2:URL のリダイレクトを追従しないと中身が空になる

:: NG: リダイレクト先のコンテンツが取れず、301/302 のレスポンスボディが保存される
curl -o "file.zip" "https://short.url/abc"  :: -L なし

:: OK: -L でリダイレクトを追従
curl -L -o "file.zip" "https://short.url/abc"

:: リダイレクト追従の最大回数(デフォルト30)を変更する場合
:: curl -L --max-redirs 10 -o "file.zip" "https://example.com/"

落とし穴3:URLにスペースや特殊文字が含まれると失敗する

:: NG: URLにスペースが含まれる場合(引用符なし)
set URL=https://example.com/my file.zip
curl -L -o file.zip %URL%  :: エラーになる

:: OK: 変数を引用符で囲む + URLのスペースを %20 にエンコード
set "URL=https://example.com/my%%20file.zip"
curl -L -f -sS -o "file.zip" "%URL%"

:: または --url オプションで明示指定
curl -L -f -sS -o "file.zip" --url "https://example.com/my file.zip"

落とし穴4:出力先ディレクトリが存在しないと失敗する

:: NG: 出力先の C:\work\downloads が存在しないと curl が失敗する
curl -L -o "C:\work\downloads\file.zip" "https://example.com/file.zip"

:: OK: 事前にディレクトリを作成する
if not exist "C:\work\downloads" mkdir "C:\work\downloads"
curl -L -f -sS -o "C:\work\downloads\file.zip" "https://example.com/file.zip"

落とし穴5:curl の exit code を即座に変数に保存しないと上書きされる

:: NG: if 文でも ERRORLEVEL が更新されることがある
curl -L -f -o "file.zip" "https://example.com/"
if %ERRORLEVEL% neq 0 (
    :: ここで別コマンドを実行すると ERRORLEVEL が上書きされる
    echo エラー
    echo %ERRORLEVEL%  :: 0 になる可能性がある
)

:: OK: ERRORLEVEL を変数に保存してから使う
curl -L -f -sS -o "file.zip" "https://example.com/"
set "DL_ERR=%ERRORLEVEL%"
if %DL_ERR% neq 0 (
    echo [ERROR] exit code: %DL_ERR%
    exit /b %DL_ERR%
)

ERRORLEVEL の詳細は ERRORLEVELを使ったエラーハンドリング完全ガイド、条件分岐は バッチファイルで条件分岐する方法完全ガイド を参照してください。

11. 実践例3本

実践例1:毎日ソフトウェアのアップデートファイルを自動ダウンロードして更新

バージョン確認 → 差分DL → 展開 → 適用 までを自動化するパターンです。

@echo off
setlocal enabledelayedexpansion

set "BASE_URL=https://example.com/releases"
set "VERSION_URL=%BASE_URL%/latest-version.txt"
set "DL_DIR=C:\work\updates"
set "CURRENT_VER_FILE=C:\work\current_version.txt"

if not exist "%DL_DIR%" mkdir "%DL_DIR%"

:: 最新バージョン番号をダウンロード
curl -L -f -sS -o "%DL_DIR%\latest.txt" "%VERSION_URL%"
if %ERRORLEVEL% neq 0 (
    echo [ERROR] バージョン確認失敗
    exit /b 1
)

:: 最新バージョンを読み取る
set "LATEST_VER="
for /f "usebackq tokens=* delims=" %%V in ("%DL_DIR%\latest.txt") do (
    set "LATEST_VER=%%V"
    goto :got_ver
)
:got_ver

:: 現在のバージョンを読み取る
set "CURRENT_VER="
if exist "%CURRENT_VER_FILE%" (
    for /f "usebackq tokens=* delims=" %%C in ("%CURRENT_VER_FILE%") do set "CURRENT_VER=%%C"
)

if "!LATEST_VER!"=="!CURRENT_VER!" (
    echo [SKIP] すでに最新版です: !CURRENT_VER!
    exit /b 0
)

echo [INFO] 新しいバージョン: !LATEST_VER! (現在: !CURRENT_VER!)

:: アップデートファイルをダウンロード
set "PKG_URL=%BASE_URL%/update-!LATEST_VER!.zip"
set "PKG_FILE=%DL_DIR%\update-!LATEST_VER!.zip"

curl -L -f -# --retry 3 --retry-delay 10 -o "!PKG_FILE!" "!PKG_URL!"
if %ERRORLEVEL% neq 0 (
    echo [ERROR] ダウンロード失敗: !PKG_URL!
    exit /b 1
)

echo [OK] ダウンロード完了: !PKG_FILE!

:: ZIP 解凍
tar -xf "!PKG_FILE!" -C "%DL_DIR%"
if %ERRORLEVEL% neq 0 (
    echo [ERROR] 解凍失敗
    exit /b 1
)

:: バージョンファイルを更新
echo !LATEST_VER!> "%CURRENT_VER_FILE%"
echo [OK] バージョン !LATEST_VER! に更新しました

ZIP解凍の詳細は バッチファイルでZIPファイルを解凍する方法完全ガイド を参照してください。

実践例2:APIのレスポンスをJSONで取得して処理結果を記録する

REST APIからデータを取得し、ファイルに保存してから PowerShell で処理するパターンです。

@echo off
setlocal enabledelayedexpansion

set "API_URL=https://api.example.com/v1/data"
set "API_KEY=your_api_key_here"
set "OUTDIR=C:\work\api"

if not exist "%OUTDIR%" mkdir "%OUTDIR%"

:: 日付付きファイル名
for /f "tokens=2 delims==." %%D in ('wmic os get LocalDateTime /value ^| findstr LocalDateTime') do set "DT=%%D"
set "OUT=%OUTDIR%\response_%DT:~0,14%.json"

:: Bearer トークン付きAPIリクエスト
curl -L -f -sS ^
     -H "Authorization: Bearer %API_KEY%" ^
     -H "Content-Type: application/json" ^
     -H "Accept: application/json" ^
     --connect-timeout 30 --max-time 60 ^
     -o "%OUT%" "%API_URL%"

set "DL_ERR=%ERRORLEVEL%"
if %DL_ERR% neq 0 (
    echo [ERROR] API取得失敗 (exit code: %DL_ERR%)
    exit /b %DL_ERR%
)

echo [OK] APIレスポンス保存: %OUT%

:: PowerShell で JSON を処理
powershell -NoProfile -Command "
    $data = Get-Content -Path "%OUT%" -Encoding UTF8 | ConvertFrom-Json
    Write-Host "件数: $($data.items.Count)"
    $data.items | Select-Object id, name | Export-Csv "%OUTDIR%\items.csv" -Encoding UTF8 -NoTypeInformation
    Write-Host "[OK] CSV出力完了"
"

if %ERRORLEVEL% neq 0 exit /b 1
echo [OK] 処理完了

実践例3:複数サイトからファイルを一括DLしてネット接続確認付きで安全に実行

事前にネット接続を確認してから複数ファイルをダウンロード、失敗分をログに記録するパターンです。

@echo off
setlocal enabledelayedexpansion

set "OUT_DIR=C:\work\downloads"
set "LOGFILE=C:\work\download_result.log"
set "SUCCESS=0"
set "FAIL=0"

if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"

:: ネットワーク接続確認(8.8.8.8 に ping)
ping -n 1 -w 3000 8.8.8.8 >nul 2>&1
if %ERRORLEVEL% neq 0 (
    echo [ERROR] ネットワーク接続なし。処理を中止します
    exit /b 1
)
echo [OK] ネットワーク接続確認

:: ダウンロードリスト(URL<TAB>ファイル名)
for %%I in (
    "https://example.com/file1.zip|report_jan.zip"
    "https://example.com/file2.zip|report_feb.zip"
    "https://example.com/file3.zip|report_mar.zip"
) do (
    for /f "tokens=1,2 delims=|" %%A in (%%I) do (
        set "DL_URL=%%A"
        set "DL_FNAME=%%B"
        echo ダウンロード中: !DL_FNAME!

        curl -L -f -sS --retry 2 --retry-delay 5 ^
             --connect-timeout 30 --max-time 300 ^
             -o "%OUT_DIR%\!DL_FNAME!" "!DL_URL!"

        if !ERRORLEVEL! equ 0 (
            set /a SUCCESS+=1
            echo [%date% %time%] OK: !DL_FNAME! >> "%LOGFILE%"
            echo  [OK] !DL_FNAME!
        ) else (
            set /a FAIL+=1
            echo [%date% %time%] FAIL: !DL_FNAME! (exit: !ERRORLEVEL!) >> "%LOGFILE%"
            echo  [FAIL] !DL_FNAME!
        )
    )
)

echo ===== 完了: 成功 !SUCCESS! 件 / 失敗 !FAIL! 件 =====
echo [%date% %time%] 完了: 成功 !SUCCESS! 件 / 失敗 !FAIL! 件 >> "%LOGFILE%"

if !FAIL! gtr 0 exit /b 1
exit /b 0

ネットワーク接続確認の詳細は ネットワーク接続の有無を判定して処理を分岐する方法 を参照してください。

12. まとめ:ダウンロード方法の使い分け表

方法 追加インストール リトライ 認証 向いているケース
curl(標準) 不要(Win10以降) ◎ –retry ◎ -u/-H ほぼ全てのケース(第一選択)
PowerShell Invoke-WebRequest 不要 △ 自前実装 cookie・複雑なHTTPヘッダー・JSON処理連携
PowerShell WebClient 不要 △ 自前実装 大容量ファイル・高速DL
bitsadmin 不要 ◎ 組み込み バックグラウンドDL・帯域制限
certutil 不要 × × 旧Windows の緊急手段(低速)

関連記事: ネットワーク接続の有無を判定する方法バッチでZIPを解凍する方法ERRORLEVELエラーハンドリング

FAQ

Q. curl コマンドが「見つかりません」と表示されます。
A. Windows 10 バージョン1803以降であれば C:\Windows\System32\curl.exe が存在します。where curl で確認してください。「見つからない」場合は PATH に C:\Windows\System32 が含まれているか確認するか、curl 公式サイト からインストールしてください。
Q. ダウンロードしたファイルが壊れている(解凍できない)ことがあります。
A. 主な原因は2つ:①リダイレクトを追従せず HTML のエラーページが保存された(-L を付ける)、②HTTP エラーのレスポンスボディが保存された(-f を付ける)。また -C - でレジュームした際に不完全なファイルが残ることがあります。その場合は一旦削除して再DLしてください。
Q. 社内プロキシ環境でダウンロードできません。
A. -x http://プロキシ:ポート でプロキシを指定するか、環境変数 HTTPS_PROXY=http://プロキシ:ポート を設定してから curl を実行してください。プロキシ認証がある場合は -U ユーザー:パスワード も追加します。
Q. ダウンロードが途中で止まることがあります。再開できますか?
A. curl -L -C - -o ファイル名 URL で前回の続きから再開(レジューム)できます。-C - は出力ファイルの既存サイズを自動検出してその続きから取得します。サーバーが Range リクエストをサポートしていない場合は最初からダウンロードされます。
Q. ダウンロードしたファイルのサイズを確認して正常かどうか判定できますか?
A. curl の -w "%{size_download}" オプションでダウンロードサイズを取得できます。また --head で事前に Content-Length を確認してから本ダウンロードする方法もあります。または for %%F in ("file.zip") do set SIZE=%%~zF で保存後のサイズを変数に取得できます。
Q. ダウンロードURLが毎日変わる場合、どう対処すればいいですか?
A. まず今日の日付を含むURLを動的に生成します。set "URL=https://example.com/data_%date:~0,4%%date:~5,2%%date:~8,2%.zip" のように%date% 変数を使ってURLを組み立てる方法が一般的です。日付と時間をファイル名に挿入する方法完全ガイド も参照してください。