【bat】バッチファイルでFTP送受信を自動化する方法完全ガイド|スクリプトファイル・アップロード・ダウンロード・エラー処理・実践例まで徹底解説

【bat】バッチファイルでFTP接続を行い、ファイルの送受信を自動化する方法 bat

毎日決まった時刻にサーバーへファイルをアップロードしたい、または定期的にリモートサーバーからファイルを取得したい。そういった要件はバッチファイルとWindowsに標準搭載されているftp コマンドで自動化できます。この記事では、バッチファイルからFTP送受信を自動化する方法を体系的に解説します。FTPスクリプトファイルを使ったヘッドレス実行の仕組みから、アップロード・ダウンロード・複数ファイル一括転送・エラー処理・パスワード管理のセキュリティ注意点まで、実践例3本とともにわかりやすく説明します。

この記事でわかること

  • Windows標準 ftp コマンドのヘッドレス実行(-s: オプション)の仕組み
  • FTPスクリプトファイルの書き方とバッチからの動的生成方法
  • アップロード(put)・ダウンロード(get)の基本
  • 複数ファイルの一括送受信(mput / mget
  • バイナリ / ASCII モードの切り替えとその必要性
  • エラー処理とログ記録のベストプラクティス
  • パスワード管理のセキュリティ注意点とSFTPへの移行方法
スポンサーリンク

1. Windows の ftp コマンドとヘッドレス実行の仕組み

Windowsには ftp.exeC:\Windows\System32\ftp.exe)が標準搭載されています。通常は対話形式で使いますが、-s:スクリプトファイル オプションを使うと、あらかじめ用意したコマンドファイルを読み込んで非対話(ヘッドレス)で実行できます。これがバッチから FTP を自動化する基本的な仕組みです。

:: 基本的な実行形式
ftp -n -s:ftpscript.txt

:: オプションの意味
::   -n   自動ログインを抑制(スクリプト内で user コマンドでログインする)
::   -s:  読み込むFTPスクリプトファイルのパスを指定
::   -i   複数ファイル転送中の確認プロンプトを抑制(mput/mget に必須)
::   -v   応答メッセージの表示を抑制(ログが増えるのを防ぐ)
FTPスクリプトコマンド 意味 書き方例
open FTPサーバーへ接続 open ftp.example.com
user ユーザー名とパスワードでログイン user ftpuser mypassword
binary バイナリ転送モードに切替 binary
ascii ASCII転送モードに切替(テキスト) ascii
put ローカル→サーバーへアップロード put local.txt remote.txt
get サーバー→ローカルへダウンロード get remote.txt local.txt
mput 複数ファイルをアップロード mput *.csv
mget 複数ファイルをダウンロード mget *.csv
cd サーバー側のディレクトリ移動 cd /upload/data
lcd ローカル側のディレクトリ移動 lcd C:\work\data
mkdir サーバー側にフォルダ作成 mkdir backup
ls / dir サーバー側のファイル一覧表示 ls
delete サーバー側のファイルを削除 delete old.txt
bye 接続を閉じる bye

2. バッチからFTPスクリプトファイルを動的に生成する方法

FTPスクリプトファイルを静的に用意しておく方法もありますが、バッチ実行時に動的に生成する方法が実務では一般的です。日付付きファイル名を転送対象にしたり、環境変数から接続先を切り替えたりできます。

@echo off

:: ─── FTP接続情報(本来は環境変数や設定ファイルから読み込む) ─
set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"
set "REMOTE_DIR=/upload/data"
set "LOCAL_FILE=C:\work\data.csv"
set "REMOTE_FILE=data.csv"

:: ─── FTPスクリプトファイルを動的生成 ─────────────────────────
set "FTP_SCRIPT=%TEMP%\ftpcmd_%RANDOM%.txt"

echo open %FTP_HOST%                     > "%FTP_SCRIPT%"
echo user %FTP_USER% %FTP_PASS%          >> "%FTP_SCRIPT%"
echo binary                              >> "%FTP_SCRIPT%"
echo cd %REMOTE_DIR%                     >> "%FTP_SCRIPT%"
echo put "%LOCAL_FILE%" %REMOTE_FILE%    >> "%FTP_SCRIPT%"
echo bye                                 >> "%FTP_SCRIPT%"

:: ─── FTP実行 ───────────────────────────────────────────────────
ftp -n -i -v -s:"%FTP_SCRIPT%"
set "FTP_RC=%ERRORLEVEL%"

:: ─── スクリプトファイルを削除(パスワードが残らないように) ──
del "%FTP_SCRIPT%" >nul 2>&1

if "%FTP_RC%"=="0" (
    echo [OK] FTP送信完了: %REMOTE_FILE%
) else (
    echo [ERROR] FTP送信失敗 ERRORLEVEL=%FTP_RC%
    exit /b 1
)
pause
FTPスクリプトファイルにはパスワードが平文で含まれる
FTPスクリプトファイルにはパスワードが平文で書かれます。%TEMP% フォルダに作成し、実行後すぐに del で削除することが重要です。ファイルが残ったままだと、ほかのユーザーに読まれる可能性があります。さらにセキュリティを高めたい場合は後述のSFTPへの移行も検討してください。
%RANDOM% でスクリプトファイル名を一意にする
同じスクリプトが並列で実行される可能性がある場合、ファイル名が衝突しないよう %RANDOM%(0〜32767のランダム値)を付加するのが安全です。%TEMP%\ftpcmd_%RANDOM%.txt のようにするとほぼ衝突しません。

3. ファイルをアップロードする(put)

3-1. 1ファイルをアップロードする基本パターン

@echo off

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"

:: ─── 日付付きレポートをアップロードする例 ──────────────────
set "YMD=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
set "LOCAL_FILE=C:\work\report_%YMD%.csv"
set "REMOTE_FILE=report_%YMD%.csv"

:: ─── ファイルの存在確認 ────────────────────────────────────
if not exist "%LOCAL_FILE%" (
    echo [ERROR] アップロード対象ファイルが見つかりません: %LOCAL_FILE%
    exit /b 1
)

set "FTP_SCRIPT=%TEMP%\ftpcmd_%RANDOM%.txt"
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo cd /upload/reports
    echo put "%LOCAL_FILE%" %REMOTE_FILE%
    echo bye
) > "%FTP_SCRIPT%"

ftp -n -i -v -s:"%FTP_SCRIPT%" >> "%~dp0logs\ftp_%YMD%.log" 2>&1
del "%FTP_SCRIPT%" >nul 2>&1

echo [%DATE% %TIME%] アップロード完了: %REMOTE_FILE%
pause

put の引数は put ローカルファイル リモートファイル名 の順です。リモートファイル名を省略すると、ローカルのファイル名と同名でアップロードされます。FTPログは >> ログファイル 2>&1 でファイルに記録することを推奨します。ログ出力の詳しい方法も参照してください。

3-2. サブフォルダへアップロードする(cd でサーバー側ディレクトリ移動)

:: ─── FTPスクリプト内で cd を使ってサーバー側のフォルダを移動 ─
echo open %FTP_HOST%       > "%FTP_SCRIPT%"
echo user %FTP_USER% %FTP_PASS% >> "%FTP_SCRIPT%"
echo binary               >> "%FTP_SCRIPT%"
echo cd /upload           >> "%FTP_SCRIPT%"
echo mkdir %YMD%          >> "%FTP_SCRIPT%"
echo cd %YMD%             >> "%FTP_SCRIPT%"
echo put "C:\work\data.csv" data.csv >> "%FTP_SCRIPT%"
echo bye                  >> "%FTP_SCRIPT%"

4. ファイルをダウンロードする(get)

4-1. 1ファイルをダウンロードする基本パターン

@echo off

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"
set "REMOTE_FILE=latest_data.csv"
set "LOCAL_DIR=C:\work\download"

:: ─── ダウンロード先フォルダを作成 ──────────────────────────
if not exist "%LOCAL_DIR%\" mkdir "%LOCAL_DIR%"

set "FTP_SCRIPT=%TEMP%\ftpcmd_%RANDOM%.txt"
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo lcd %LOCAL_DIR%
    echo cd /download
    echo get %REMOTE_FILE%
    echo bye
) > "%FTP_SCRIPT%"

ftp -n -i -v -s:"%FTP_SCRIPT%"
set "RC=%ERRORLEVEL%"
del "%FTP_SCRIPT%" >nul 2>&1

if "%RC%"=="0" (
    echo [OK] ダウンロード完了: %LOCAL_DIR%\%REMOTE_FILE%
) else (
    echo [ERROR] ダウンロード失敗 ERRORLEVEL=%RC%
    exit /b 1
)
pause

get の引数は get リモートファイル [ローカルファイル名] です。ローカルファイル名を省略するとリモートと同名でダウンロードされます。lcd(local change directory)でローカルの保存先フォルダを移動してから get を実行すると、任意のフォルダに保存できます。

5. 複数ファイルを一括転送する(mput / mget)

ワイルドカードで複数ファイルを一括転送するには mput(アップロード)または mget(ダウンロード)を使います。-i オプション(確認プロンプトの抑制)が必須です。忘れると各ファイルごとに「y/n?」と聞かれてバッチが止まります。

@echo off

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"

set "FTP_SCRIPT=%TEMP%\ftpcmd_%RANDOM%.txt"

:: ─── 複数CSVファイルをアップロード(mput) ────────────────
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo lcd C:\work\data
    echo cd /upload
    echo mput *.csv
    echo bye
) > "%FTP_SCRIPT%"

:: -i オプションで確認プロンプトを抑制することが必須
ftp -n -i -v -s:"%FTP_SCRIPT%"
del "%FTP_SCRIPT%" >nul 2>&1

:: ─── 複数ファイルをダウンロード(mget) ───────────────────
set "FTP_SCRIPT2=%TEMP%\ftpcmd_%RANDOM%.txt"
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo lcd C:\work\download
    echo cd /download
    echo mget *.csv
    echo bye
) > "%FTP_SCRIPT2%"

ftp -n -i -v -s:"%FTP_SCRIPT2%"
del "%FTP_SCRIPT2%" >nul 2>&1
pause
mput / mget は Windows の ftp.exe ではワイルドカード動作に注意
Windows標準の ftp.exe では mput *.csv がローカル側のワイルドカード展開をサポートしない場合があります。mget はサーバー側、mput はローカル側のパターンマッチですが、動作がサーバーの実装に依存することがあります。確実に複数ファイルを転送したい場合は、バッチの for ループで1ファイルずつ put する方法(後述)が安全です。

6. for ループで複数ファイルを確実に1件ずつ転送する

mput が不安定な場合や、転送ごとに結果を記録したい場合は、バッチの for ループで対象ファイルを1件ずつ転送する方法が堅牢です。

@echo off
setlocal enabledelayedexpansion

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"
set "LOCAL_DIR=C:\work\data"
set "REMOTE_DIR=/upload/data"
set "LOG_FILE=%~dp0logs\ftp_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"

if not exist "%~dp0logs\" mkdir "%~dp0logs"

set /a "OK=0"
set /a "NG=0"

:: ─── 対象フォルダの全CSVを1件ずつアップロード ──────────
for %%F in ("%LOCAL_DIR%\*.csv") do (
    set "FTP_SCRIPT=%TEMP%\ftpcmd_!RANDOM!.txt"
    (
        echo open %FTP_HOST%
        echo user %FTP_USER% %FTP_PASS%
        echo binary
        echo cd %REMOTE_DIR%
        echo put "%%F" %%~nxF
        echo bye
    ) > "!FTP_SCRIPT!"

    ftp -n -i -v -s:"!FTP_SCRIPT!" >> "%LOG_FILE%" 2>&1
    set "RC=!ERRORLEVEL!"
    del "!FTP_SCRIPT!" >nul 2>&1

    if "!RC!"=="0" (
        echo [%DATE% %TIME%] [OK] %%~nxF >> "%LOG_FILE%"
        set /a "OK+=1"
    ) else (
        echo [%DATE% %TIME%] [NG] %%~nxF ERRORLEVEL=!RC! >> "%LOG_FILE%"
        set /a "NG+=1"
    )
)

echo [%DATE% %TIME%] 完了 OK=!OK! NG=!NG! >> "%LOG_FILE%"
echo 完了: OK=!OK! NG=!NG!  ログ: %LOG_FILE%
pause

7. バイナリ / ASCII モードの切り替えと注意点

FTPには バイナリモードASCIIモードの2種類の転送モードがあります。モードを間違えるとファイルが壊れる原因になります。

モード コマンド 用途 注意点
バイナリ(推奨) binary ZIP・画像・Excel・PDF・実行ファイルなどすべてのファイル ほぼすべての場合に使うべき。改行コードを変換しない
ASCII ascii テキストファイル(改行コードをOS間で自動変換したいとき) Windows(CRLF)↔Unix(LF)の変換が入る。バイナリに使うと壊れる
よほどの理由がない限り binary を使う
ASCIIモードはWindowsとUnix間のテキストファイル転送で改行コードを自動変換する機能ですが、バイナリファイルに適用するとファイルが壊れます。FTPスクリプトには常に binary を明示的に指定する習慣をつけましょう。接続直後のデフォルトモードはサーバーによって異なります。

8. FTP のエラー処理とログ記録の注意点

8-1. ERRORLEVEL の落とし穴

Windows の ftp.exe はエラーが発生しても ERRORLEVEL が 0 を返すことがあります。たとえば接続先ファイルが存在しなくて get が失敗した場合でも、ftp コマンド自体の終了コードは 0 になることが多いです。このため、FTP の成否を確認するには FTPログを解析する方法が最も確実です。

@echo off
setlocal enabledelayedexpansion

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"
set "FTP_LOG=%TEMP%\ftp_result_%RANDOM%.log"
set "FTP_SCRIPT=%TEMP%\ftpcmd_%RANDOM%.txt"

(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo put "C:\work\data.csv" data.csv
    echo bye
) > "%FTP_SCRIPT%"

:: ─── FTP実行ログをファイルに保存 ───────────────────────────
ftp -n -i -v -s:"%FTP_SCRIPT%" > "%FTP_LOG%" 2>&1
del "%FTP_SCRIPT%" >nul 2>&1

:: ─── ログ内に成功メッセージがあるか確認 ─────────────────
findstr /i "226 Transfer complete" "%FTP_LOG%" >nul 2>&1
if %ERRORLEVEL%==0 (
    echo [OK] FTP送信成功
) else (
    echo [ERROR] FTP送信失敗。ログを確認してください: %FTP_LOG%
    type "%FTP_LOG%"
    exit /b 1
)
del "%FTP_LOG%" >nul 2>&1
pause
FTPの成功を示す応答コード

  • 226 Transfer complete — ファイル転送が正常完了
  • 230 Login successful — ログイン成功
  • 220 — FTPサーバーへの接続成功
  • 550 — ファイルが見つからない・権限エラー(失敗)
  • 530 — ログイン失敗(ユーザー名/パスワード誤り)

FTPの応答ログに 226 があれば転送成功、550530 があれば失敗です。findstr でこれらのコードをチェックするのが確実な成否判定方法です。

8-2. ネットワーク接続を事前確認してからFTPを実行する

ネットワークが不安定な環境では、FTP実行前に接続確認を行うことを推奨します。ネットワーク接続の有無を判定して処理を分岐する方法も参照してください。

@echo off

set "FTP_HOST=ftp.example.com"

:: ─── ping で接続確認(1回・タイムアウト3秒) ──────────────
ping -n 1 -w 3000 %FTP_HOST% >nul 2>&1
if %ERRORLEVEL% neq 0 (
    echo [ERROR] %FTP_HOST% に到達できません。FTP処理を中止します
    exit /b 1
)
echo [OK] ネットワーク接続確認済み

:: ─── FTP処理へ続く ─────────────────────────────────────────

9. パスワード管理のセキュリティ注意点

バッチファイルへのパスワード直書きは危険
バッチファイルにFTPパスワードを直接書くと、そのファイルを読める人全員にパスワードが漏れます。タスクスケジューラで実行するサーバー環境では特に注意が必要です。

9-1. 環境変数でパスワードを外部から注入する

パスワードをバッチファイルに直書きせず、実行前に環境変数としてセットする方法が比較的安全です。タスクスケジューラやCI環境ではシークレット変数から渡せます。

:: 別のスクリプトや環境からパスワードを渡す場合
:: set FTP_PASS=実際のパスワード  ← 実行環境でセット
@echo off

if "%FTP_PASS%"=="" (
    echo [ERROR] 環境変数 FTP_PASS が設定されていません
    exit /b 1
)

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
:: FTP_PASS は環境変数から取得(バッチ内に直書きしない)

set "FTP_SCRIPT=%TEMP%\ftpcmd_%RANDOM%.txt"
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo put "C:\work\data.csv" data.csv
    echo bye
) > "%FTP_SCRIPT%"

ftp -n -i -v -s:"%FTP_SCRIPT%"
del "%FTP_SCRIPT%" >nul 2>&1

9-2. SFTPへの移行を検討する

FTPは通信が暗号化されていません。ユーザー名・パスワード・ファイルの中身がすべて平文でネットワークを流れます。社内ネットワークであっても、セキュリティ要件が厳しい環境では SFTP(SSH File Transfer Protocol)への移行を検討してください。WinSCPをバッチから使う方法は WinSCPを使ったSFTP接続とファイル送受信の方法で詳しく解説しています。

項目 FTP SFTP(WinSCP)
通信の暗号化 ❌ 平文 ✅ SSH暗号化
標準搭載 ✅ Windows標準 ❌ WinSCPを別途インストール
パスワード認証 ✅ 対応 ✅ 対応
公開鍵認証 ❌ 非対応 ✅ 対応(パスワード不要)
エラー処理 △ ERRORLEVEL不安定 ✅ 終了コードが明確
ファイル一括転送 △ mput動作が不安定 ✅ /synchronize などが使いやすい
推奨環境 社内・レガシーシステム インターネット経由・機密データ

10. 実践例3本

実践例1:毎日の売上CSVを日付付きでFTPアップロードする

タスクスケジューラと組み合わせて毎朝9時に実行する想定の、日次バッチファイルの定番パターンです。日付をファイル名に使う方法と組み合わせています。

@echo off
setlocal enabledelayedexpansion

:: ─── 設定 ──────────────────────────────────────────────────
set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"
set "YMD=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
set "LOCAL_FILE=C:\work\sales\sales_%YMD%.csv"
set "REMOTE_FILE=sales_%YMD%.csv"
set "LOG_DIR=%~dp0logs"
set "LOG_FILE=%LOG_DIR%\ftp_upload_%YMD%.log"

if not exist "%LOG_DIR%\" mkdir "%LOG_DIR%"

:: ─── ファイル存在確認 ───────────────────────────────────────
if not exist "%LOCAL_FILE%" (
    echo [%DATE% %TIME%] [ERROR] 対象ファイルなし: %LOCAL_FILE% >> "%LOG_FILE%"
    exit /b 1
)

:: ─── ネットワーク確認 ───────────────────────────────────────
ping -n 1 -w 3000 %FTP_HOST% >nul 2>&1
if %ERRORLEVEL% neq 0 (
    echo [%DATE% %TIME%] [ERROR] FTPサーバーに到達不可 >> "%LOG_FILE%"
    exit /b 1
)

:: ─── FTP実行 ────────────────────────────────────────────────
set "FTP_SCRIPT=%TEMP%\ftpcmd_!RANDOM!.txt"
set "FTP_RESULT=%TEMP%\ftpresult_!RANDOM!.txt"
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo cd /upload/sales
    echo put "%LOCAL_FILE%" %REMOTE_FILE%
    echo bye
) > "!FTP_SCRIPT!"

ftp -n -i -v -s:"!FTP_SCRIPT!" > "!FTP_RESULT!" 2>&1
type "!FTP_RESULT!" >> "%LOG_FILE%"
del "!FTP_SCRIPT!" >nul 2>&1

:: ─── 成否をログ解析で確認 ──────────────────────────────────
findstr /i "226 Transfer complete" "!FTP_RESULT!" >nul 2>&1
if !ERRORLEVEL!==0 (
    echo [%DATE% %TIME%] [OK] アップロード成功: %REMOTE_FILE% >> "%LOG_FILE%"
    echo [OK] アップロード完了
) else (
    echo [%DATE% %TIME%] [ERROR] アップロード失敗 >> "%LOG_FILE%"
    echo [ERROR] アップロード失敗。ログ: %LOG_FILE%
)
del "!FTP_RESULT!" >nul 2>&1
pause

実践例2:リモートサーバーからデータファイルを定期ダウンロードする

リモートサーバーの特定フォルダから複数のCSVをダウンロードして日付付きフォルダに保存する定期実行バッチの例です。

@echo off
setlocal enabledelayedexpansion

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"
set "YMD=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
set "DOWNLOAD_DIR=C:\work\download\%YMD%"
set "LOG_FILE=%~dp0logs\ftp_download_%YMD%.log"

if not exist "%DOWNLOAD_DIR%\" mkdir "%DOWNLOAD_DIR%"
if not exist "%~dp0logs\" mkdir "%~dp0logs"

echo [%DATE% %TIME%] ダウンロード開始 >> "%LOG_FILE%"

set "FTP_SCRIPT=%TEMP%\ftpcmd_!RANDOM!.txt"
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo lcd %DOWNLOAD_DIR%
    echo cd /data/export
    echo mget *.csv
    echo bye
) > "!FTP_SCRIPT!"

ftp -n -i -v -s:"!FTP_SCRIPT!" >> "%LOG_FILE%" 2>&1
del "!FTP_SCRIPT!" >nul 2>&1

echo [%DATE% %TIME%] ダウンロード完了 保存先: %DOWNLOAD_DIR% >> "%LOG_FILE%"
echo 完了。保存先: %DOWNLOAD_DIR%
pause

実践例3:アップロード後にリモートの古いファイルを削除する

新しいファイルをアップロードした後、サーバー側の古いファイルを FTPスクリプト内の delete で削除するパターンです。サーバー側のディスクが逼迫しないよう定期的に行う運用に使えます。

@echo off
setlocal enabledelayedexpansion

set "FTP_HOST=ftp.example.com"
set "FTP_USER=ftpuser"
set "FTP_PASS=mypassword"
set "YMD=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"

:: ─── 昨日の日付を計算(PowerShellで取得) ─────────────────
for /f %%d in ('powershell -NoProfile -Command "Get-Date (Get-Date).AddDays(-1) -Format yyyyMMdd"') do set "YESTERDAY=%%d"

set "FTP_SCRIPT=%TEMP%\ftpcmd_!RANDOM!.txt"
(
    echo open %FTP_HOST%
    echo user %FTP_USER% %FTP_PASS%
    echo binary
    echo cd /upload/daily
    echo put "C:\work\daily_%YMD%.csv" daily_%YMD%.csv
    echo delete daily_%YESTERDAY%.csv
    echo bye
) > "!FTP_SCRIPT!"

ftp -n -i -v -s:"!FTP_SCRIPT!" >> "%~dp0logs\ftp_%YMD%.log" 2>&1
del "!FTP_SCRIPT!" >nul 2>&1

echo [OK] %YMD% アップロード + %YESTERDAY% 削除完了
pause

11. まとめ:FTP バッチ チートシート

やりたいこと FTPスクリプト記述例 / コマンド 備考
サーバー接続 open ftp.example.com
ログイン user ユーザー名 パスワード ftp -n と組み合わせて使う
バイナリモード(必須) binary 常に指定する
サーバー側ディレクトリ移動 cd /remote/path
ローカル側ディレクトリ移動 lcd C:\local\path
アップロード put "local.csv" remote.csv 引数: ローカル リモート
ダウンロード get remote.csv local.csv 引数: リモート ローカル
複数ファイルアップロード mput *.csv -iオプション必須
複数ファイルダウンロード mget *.csv -iオプション必須
サーバー側フォルダ作成 mkdir backup
サーバー側ファイル削除 delete old.csv
ヘッドレス実行 ftp -n -i -v -s:script.txt 非対話モードの基本形
成功確認 findstr "226 Transfer complete" ログ ERRORLEVEL は不安定
スクリプトファイル後始末 FTP実行後すぐ del パスワード漏えい防止

FAQ

Qftp コマンドで「接続できない」エラーが出ます。原因は何ですか?

A主な原因は3つです。①ホスト名・ポート番号が間違っている(FTPのデフォルトポートは21)、②Windowsファイアウォールがブロックしている、③サーバー側でActiveモードのみ許可されているのにクライアントがPassiveモードで接続しようとしている。特にNATやルーター越えの場合はPassiveモードが必要なことが多いですが、Windows標準の ftp.exe はPassiveモードの対応が限定的です。その場合はWinSCPや curlを使った方法の利用を検討してください。

QFTP送信は成功しているのにERRORLEVELが0以外になります。

AWindows の ftp.exe はその逆で「失敗してもERRORLEVELが0を返す」ことが多いです。ERRORLEVELが0以外になるのは稀なケース(接続先が存在しないなど)です。FTPの成否を確実に判定するには、FTPの出力を > ログファイル に保存し、findstr "226 Transfer complete" で成功応答コードを確認する方法が確実です。

QFTPスクリプトファイルにパスワードを書かずに実行する方法はありますか?

A完全な回避は難しいですが、いくつかの軽減策があります。①環境変数からパスワードを渡してスクリプトを実行時に動的生成する、②スクリプトファイルのパーミッションを本人のみ読み取り可能にする(icaclsで設定)、③そもそもSFTP+公開鍵認証に移行してパスワード不要にする(WinSCPでのSFTP方法参照)。公開鍵認証ではパスワード自体が不要になるため、最も安全です。

Qftp コマンドで日本語ファイル名を転送できますか?

A困難なケースが多いです。Windows の ftp.exe はコードページの扱いが古く、日本語(マルチバイト)ファイル名が文字化けしたり、正しく転送できないことがあります。日本語ファイル名が含まれる場合は、WinSCPなどのFTPクライアントを利用するか、英数字のみのファイル名にリネームしてから転送することを推奨します。

QFTPで特定のポート番号を指定したい場合はどうすればよいですか?

AWindows標準の ftp コマンドでは open ホスト名 ポート番号 のようにopen コマンドにポート番号を続けて指定できます(例: open ftp.example.com 2121)。FTPスクリプトファイルの1行目を open ftp.example.com 2121 とするだけです。

QFTPとSFTPはどちらを選ぶべきですか?

Aセキュリティの観点から、可能であれば常に SFTP を選ぶべきです。FTPは通信が平文で暗号化されていないため、パスワードやファイル内容が盗聴リスクにさらされます。ただしレガシーシステムや社内ネットワーク限定でFTPしか使えない環境では、ファイアウォールで接続元IPを制限しつつFTPを使い続けるケースもあります。WinSCPを使ったSFTP接続の方法で移行手順を確認できます。