バッチファイルで自動バックアップを作成する方法【Windows完全ガイド】

バッチファイル(.bat)を使えば、ファイルのコピーからデータベースバックアップ、圧縮、ログ出力までをすべて自動化できます。

手動バックアップは「忘れる」「手順を間違える」「時間がかかる」の三重苦。バッチファイルでこの問題を根本から解決しましょう。

この記事では、基本的なファイルバックアップから日付付き世代管理DB バックアップ圧縮・通知・タスクスケジューラ連携まで、実務で使えるバックアップバッチを網羅的に解説します。

スポンサーリンク

バッチファイル(.bat)とは

バッチファイルは、Windows のコマンド(CMD)を順番に記述したテキストファイルです。拡張子を .bat にして保存するだけで、ダブルクリックで実行できます。

項目 内容
拡張子 .bat または .cmd
実行方法 ダブルクリック / コマンドプロンプト / タスクスケジューラ
文字コード Shift_JIS(日本語Windows標準)
メリット 追加ソフト不要・軽量・スケジュール実行が容易

ポイント:バッチファイルは Windows に標準搭載されている機能だけで動作するため、サーバーやPCに追加のソフトウェアをインストールする必要がありません。

最小構成のバッチファイルは以下のとおりです。

hello.bat
@echo off
rem 画面に表示されるメッセージ
echo Hello, Batch File!
pause

@echo off はコマンド自体の表示を抑制し、pause は実行後にウィンドウが閉じないようにします。

基本のファイルバックアップ(xcopy / robocopy)

Windows でファイルをコピーするコマンドは主に xcopyrobocopy の2つがあります。

xcopy でバックアップ

xcopy は Windows 2000 以降で使える軽量なコピーコマンドです。

backup-xcopy.bat
@echo off
setlocal

rem バックアップ元とバックアップ先
set SOURCE=C:\Projects\MyApp
set DEST=D:\Backup\MyApp

rem xcopy でサブフォルダ含む全ファイルをコピー
xcopy "%SOURCE%" "%DEST%" /E /Y /I /D

echo バックアップが完了しました。
endlocal
オプション 説明
/E 空のサブディレクトリも含めてコピー
/Y 上書き確認を省略
/I コピー先がフォルダであると見なす
/D 更新されたファイルのみコピー(差分コピー)

robocopy でバックアップ

robocopy(Robust File Copy)は Windows Vista 以降に標準搭載された高機能コピーコマンドです。

backup-robocopy.bat
@echo off
setlocal

rem バックアップ元とバックアップ先
set SOURCE=C:\Projects\MyApp
set DEST=D:\Backup\MyApp

rem robocopy でミラーリングバックアップ
robocopy "%SOURCE%" "%DEST%" /MIR /FFT /Z /XA:SH /R:3 /W:5

echo バックアップが完了しました。
endlocal
オプション 説明
/MIR ミラーリング(元にないファイルは先からも削除)
/FFT FAT ファイルシステムのタイムスタンプ許容
/Z 再起動可能モード(中断しても再開できる)
/XA:SH システム・隠しファイルを除外
/R:3 失敗時のリトライ回数(デフォルト100万回)
/W:5 リトライ間隔(秒、デフォルト30秒)

注意:/MIR はバックアップ先にしか存在しないファイルを削除します。初回実行前にバックアップ先のパスが正しいことを必ず確認してください。

xcopy と robocopy の違いと使い分け

比較項目 xcopy robocopy
ミラーリング 不可 対応(/MIR)
リトライ機能 なし あり(/R, /W)
ログ出力 リダイレクトのみ /LOG オプション
マルチスレッド 非対応 対応(/MT)
中断からの再開 不可 対応(/Z)
推奨用途 小規模・単発コピー 定期バックアップ・大規模

使い分けの目安

  • xcopy:ちょっとしたファイルコピー、Windows XP などの古い環境
  • robocopy:定期バックアップ、大量ファイル、ネットワーク越しのコピー
  • 迷ったら robocopy を選択するのが安全です

日付付きフォルダでバックアップを管理する

バックアップ先を日付付きのフォルダにすると、「いつ時点のデータか」が一目でわかります。

backup-dated.bat
@echo off
setlocal

rem 日付を YYYYMMDD 形式で取得
set YYYY=%DATE:~0,4%
set MM=%DATE:~5,2%
set DD=%DATE:~8,2%
set TODAY=%YYYY%%MM%%DD%

rem バックアップ先を日付フォルダに
set SOURCE=C:\Projects\MyApp
set DEST=D:\Backup\%TODAY%

rem フォルダを作成してバックアップ
mkdir "%DEST%" 2>nul
robocopy "%SOURCE%" "%DEST%" /E /R:3 /W:5

echo [%TODAY%] バックアップ完了: %DEST%
endlocal

実行結果

D:\Backup\20260305\  ← 今日の日付でフォルダが作成される

ポイント:%DATE% の形式は Windows の地域設定に依存します。日本語環境では 2026/03/05 形式が一般的ですが、環境によっては wmic os get localdatetime を使うと確実です。

N世代バックアップ(古いバックアップの自動削除)

日付付きバックアップを続けていると、ディスクがいっぱいになります。N世代分だけ保持し、古いものを自動削除する仕組みを追加しましょう。

backup-generation.bat
@echo off
setlocal enabledelayedexpansion

rem === 設定 ===
set SOURCE=C:\Projects\MyApp
set BACKUP_ROOT=D:\Backup
set KEEP_GENERATIONS=7

rem === 日付取得 ===
set YYYY=%DATE:~0,4%
set MM=%DATE:~5,2%
set DD=%DATE:~8,2%
set TODAY=%YYYY%%MM%%DD%
set DEST=%BACKUP_ROOT%\%TODAY%

rem === バックアップ実行 ===
mkdir "%DEST%" 2>nul
robocopy "%SOURCE%" "%DEST%" /E /R:3 /W:5

rem === 古い世代を削除 ===
set COUNT=0
for /f "delims=" %%d in ('dir /b /ad /o-n "%BACKUP_ROOT%"') do (
    set /a COUNT+=1
    if !COUNT! gtr %KEEP_GENERATIONS% (
        echo 削除: %BACKUP_ROOT%\%%d
        rd /s /q "%BACKUP_ROOT%\%%d"
    )
)

echo バックアップ完了(%KEEP_GENERATIONS%世代保持)
endlocal

このスクリプトは dir /o-n(名前の降順)でフォルダ一覧を取得し、KEEP_GENERATIONS を超えた分を自動削除します。日付フォルダ名(YYYYMMDD)のおかげで、名前順=日付順になります。

ログ出力を追加する

バックアップの実行記録を残しておくと、問題が起きたときの調査に役立ちます。

robocopy のログオプション

robocopy には標準でログ出力オプションが用意されています。

ログ付きバックアップ
rem ログファイルのパスを設定
set LOGFILE=D:\Backup\logs\backup_%TODAY%.log

rem ログ出力付きでバックアップ
robocopy "%SOURCE%" "%DEST%" /E /R:3 /W:5 /LOG:"%LOGFILE%" /NP /TEE
オプション 説明
/LOG:ファイル 指定ファイルにログ出力(上書き)
/LOG+:ファイル 指定ファイルにログ追記
/NP 進捗率の表示を省略(ログの可読性向上)
/TEE ログ出力と画面表示の両方を行う

独自のログ関数を作る

より詳細なログが必要な場合は、タイムスタンプ付きのログ関数を自作します。

タイムスタンプ付きログ関数
:LOG
rem タイムスタンプ付きでログを書き込む
set MSG=%~1
echo [%DATE% %TIME%] %MSG%
echo [%DATE% %TIME%] %MSG% >> "%LOGFILE%"
goto :EOF

rem 使い方
call :LOG "バックアップを開始します"
call :LOG "バックアップが完了しました"

エラーハンドリング(ERRORLEVEL)

バッチファイルでは、コマンドの実行結果が %ERRORLEVEL% に格納されます。この値を使ってエラー処理を行いましょう。

基本的なエラーチェック

エラーハンドリング付きバックアップ
@echo off
setlocal

set SOURCE=C:\Projects\MyApp
set DEST=D:\Backup\MyApp

rem バックアップ元の存在確認
if not exist "%SOURCE%" (
    echo [エラー] バックアップ元が見つかりません: %SOURCE%
    exit /b 1
)

rem バックアップ実行
robocopy "%SOURCE%" "%DEST%" /MIR /R:3 /W:5
set RC=%ERRORLEVEL%

rem robocopy の戻り値を判定
if %RC% geq 8 (
    echo [エラー] バックアップに失敗しました(コード: %RC%)
    exit /b %RC%
) else (
    echo [成功] バックアップが完了しました
)

endlocal

robocopy の戻り値

robocopy は通常のコマンドと異なる戻り値の体系を持っています。

戻り値 意味 対応
0 変更なし(コピー不要) 正常
1 ファイルがコピーされた 正常
2 余分なファイルが検出された 正常(/MIR 使用時)
4 不一致が検出された 要確認
8以上 コピー失敗あり エラー対応必要
16 致命的エラー 即座に調査

robocopy の戻り値の考え方

  • 0〜3:正常(コピー成功 or 変更なし)
  • 4〜7:警告(一部不一致あり、要確認)
  • 8以上:エラー(コピー失敗あり、対応が必要)

タスクスケジューラで自動実行する

作成したバッチファイルを Windows のタスクスケジューラに登録すると、毎日・毎週・毎月など決まったスケジュールで自動実行できます。

GUI で設定する手順

  1. Win + Rtaskschd.msc でタスクスケジューラを起動
  2. 右側の「タスクの作成」をクリック
  3. 「全般」タブ:タスク名(例: DailyBackup)を入力、「最上位の特権で実行する」にチェック
  4. 「トリガー」タブ:「新規」→ 毎日 / 指定時刻を設定
  5. 「操作」タブ:「新規」→ プログラムにバッチファイルのパスを指定
  6. 「条件」タブ:「AC 電源の場合のみ」のチェックを外す(ノートPCの場合)
  7. 「設定」タブ:「タスクが失敗した場合、再起動する」にチェック

コマンドラインで登録する

schtasks コマンドを使えば、コマンドラインからも登録できます。

タスクスケジューラへの登録
rem 毎日 02:00 にバックアップを実行
schtasks /Create /TN "DailyBackup" /TR "D:\scripts\backup.bat" /SC DAILY /ST 02:00 /RL HIGHEST

rem 登録済みタスクの確認
schtasks /Query /TN "DailyBackup"

rem タスクの削除
schtasks /Delete /TN "DailyBackup" /F
オプション 説明
/TN タスク名
/TR 実行するプログラムのパス
/SC スケジュール種類(DAILY, WEEKLY, MONTHLY)
/ST 開始時刻(HH:MM 形式)
/RL HIGHEST 最上位の特権で実行

データベースのバックアップ(MySQL / PostgreSQL)

Web アプリケーションの運用では、ファイルだけでなくデータベースのバックアップも必須です。

MySQL のバックアップ

backup-mysql.bat
@echo off
setlocal

rem === MySQL 接続情報 ===
set MYSQL_BIN=C:\xampp\mysql\bin
set DB_HOST=localhost
set DB_PORT=3306
set DB_USER=root
set DB_NAME=my_database

rem === 出力先 ===
set YYYY=%DATE:~0,4%
set MM=%DATE:~5,2%
set DD=%DATE:~8,2%
set DUMP_FILE=D:\Backup\db\%DB_NAME%_%YYYY%%MM%%DD%.sql

rem === ダンプ実行 ===
"%MYSQL_BIN%\mysqldump" -h %DB_HOST% -P %DB_PORT% -u %DB_USER% --single-transaction --routines --triggers %DB_NAME% > "%DUMP_FILE%"

if %ERRORLEVEL% equ 0 (
    echo [成功] MySQL バックアップ完了: %DUMP_FILE%
) else (
    echo [エラー] MySQL バックアップに失敗しました
    exit /b 1
)

endlocal
オプション 説明
--single-transaction InnoDB のロックなしバックアップ
--routines ストアドプロシージャも含める
--triggers トリガーも含める

PostgreSQL のバックアップ

backup-postgres.bat
@echo off
setlocal

rem === PostgreSQL 接続情報 ===
set PG_BIN=C:\Program Files\PostgreSQL\16\bin
set PGHOST=localhost
set PGPORT=5432
set PGUSER=postgres
set PGDATABASE=my_database

rem === ダンプ実行 ===
set DUMP_FILE=D:\Backup\db\%PGDATABASE%_%YYYY%%MM%%DD%.dump

"%PG_BIN%\pg_dump" -Fc -Z 9 -f "%DUMP_FILE%" %PGDATABASE%

if %ERRORLEVEL% equ 0 (
    echo [成功] PostgreSQL バックアップ完了: %DUMP_FILE%
) else (
    echo [エラー] PostgreSQL バックアップに失敗しました
)

endlocal

ポイント:PostgreSQL でパスワード入力を省略するには、%APPDATA%\postgresql\pgpass.conf にパスワードを記述します(形式: host:port:database:user:password)。

バックアップを圧縮する(7-Zip 連携)

バックアップファイルを圧縮すると、ディスク容量を節約できます。7-Zip のコマンドライン版(7z.exe)を使うのが定番です。

backup-compress.bat
@echo off
setlocal

rem === 設定 ===
set SEVEN_ZIP="C:\Program Files\7-Zip\7z.exe"
set SOURCE=D:\Backup\20260305
set ARCHIVE=D:\Backup\archives\backup_20260305.7z

rem === 圧縮実行(最高圧縮率) ===
%SEVEN_ZIP% a -t7z -mx=9 -mmt=on "%ARCHIVE%" "%SOURCE%\*"

if %ERRORLEVEL% equ 0 (
    echo [成功] 圧縮完了: %ARCHIVE%
    rem 元フォルダを削除して容量節約
    rd /s /q "%SOURCE%"
) else (
    echo [エラー] 圧縮に失敗しました
)

endlocal
オプション 説明
a アーカイブに追加
-t7z 7z 形式で圧縮
-mx=9 最高圧縮率
-mmt=on マルチスレッド圧縮
-p{パスワード} パスワード付き圧縮

ポイント:パスワード付きで圧縮するには -pMySecretPassword のように指定します。機密データのバックアップには必ず暗号化を設定しましょう。

バックアップ結果をメール通知する

バックアップの成功・失敗をメールで通知する仕組みを追加すると、異常にすぐ気付けます。

PowerShell 経由でメール送信

バッチファイルから PowerShell を呼び出してメール送信します。

メール通知の関数
:SEND_MAIL
rem 引数: %~1=件名, %~2=本文
powershell -Command "^
  $smtp = New-Object Net.Mail.SmtpClient('smtp.gmail.com', 587);^
  $smtp.EnableSsl = $true;^
  $smtp.Credentials = New-Object Net.NetworkCredential('your@gmail.com', 'app-password');^
  $smtp.Send('from@gmail.com', 'to@example.com', '%~1', '%~2')^
"
goto :EOF

rem 使い方
call :SEND_MAIL "[成功] バックアップ完了" "バックアップが正常に完了しました。"

注意:Gmail を使う場合は「アプリパスワード」の発行が必要です。通常のパスワードでは認証できません。Google アカウントの「セキュリティ」→「アプリパスワード」から発行してください。

バッチファイル vs PowerShell:どちらを使うべきか

Windows でのスクリプト実行は、バッチファイル以外に PowerShell という選択肢もあります。

比較項目 バッチファイル (.bat) PowerShell (.ps1)
学習コスト 低い やや高い
実行ポリシー 制限なし 要設定(Set-ExecutionPolicy)
文字列処理 苦手 得意(正規表現対応)
エラー処理 ERRORLEVEL のみ try/catch 対応
メール送信 外部ツール必要 標準コマンドレット
互換性 すべてのWindows Windows 7 SP1 以降
推奨用途 シンプルな自動化 複雑なロジック

PowerShell版バックアップスクリプトの例

参考として、同等の処理を PowerShell で書いた場合の例です。

backup.ps1(PowerShell版)
# PowerShell版バックアップスクリプト
$Source  = "C:\Projects\MyApp"
$BackupRoot = "D:\Backup"
$Today  = Get-Date -Format "yyyyMMdd"
$Dest   = Join-Path $BackupRoot $Today

try {
    # バックアップ実行
    Copy-Item -Path $Source -Destination $Dest -Recurse -Force
    Write-Host "[成功] バックアップ完了: $Dest" -ForegroundColor Green

    # 世代管理(7世代)
    Get-ChildItem $BackupRoot -Directory |
        Sort-Object Name -Descending |
        Select-Object -Skip 7 |
        Remove-Item -Recurse -Force
} catch {
    Write-Host "[エラー] $($_.Exception.Message)" -ForegroundColor Red
}

使い分けの指針

  • robocopy でファイルをコピーするだけなら バッチファイル で十分
  • メール通知・JSON パース・REST API 連携が必要なら PowerShell
  • 古い Windows Server(2003/2008)では バッチファイル 一択
  • バッチから PowerShell を powershell -File script.ps1 で呼び出すハイブリッド構成もおすすめ

実務で使える完全版バックアップテンプレート

ここまでの内容を統合した、実務でそのまま使えるバックアップバッチファイルのテンプレートです。

full-backup.bat(完全版テンプレート)
@echo off
setlocal enabledelayedexpansion

rem ==========================================
rem  自動バックアップスクリプト(完全版)
rem  ファイル + DB + 圧縮 + 世代管理 + ログ
rem ==========================================

rem === 基本設定 ===
set SOURCE=C:\Projects\MyApp
set BACKUP_ROOT=D:\Backup
set KEEP_GENERATIONS=7
set SEVEN_ZIP="C:\Program Files\7-Zip\7z.exe"

rem === DB設定(不要なら空欄) ===
set MYSQL_BIN=C:\xampp\mysql\bin
set DB_HOST=localhost
set DB_PORT=3306
set DB_USER=root
set DB_NAME=my_database

rem === 日付・パス設定 ===
set YYYY=%DATE:~0,4%
set MM=%DATE:~5,2%
set DD=%DATE:~8,2%
set TODAY=%YYYY%%MM%%DD%
set DEST=%BACKUP_ROOT%\%TODAY%
set LOGDIR=%BACKUP_ROOT%\logs
set LOGFILE=%LOGDIR%\backup_%TODAY%.log
set ERRORS=0

rem === ディレクトリ作成 ===
mkdir "%DEST%" 2>nul
mkdir "%LOGDIR%" 2>nul

call :LOG "========== バックアップ開始 =========="

rem === 1. ファイルバックアップ ===
call :LOG "[STEP 1] ファイルバックアップ開始"
robocopy "%SOURCE%" "%DEST%\files" /E /R:3 /W:5 /NP /LOG+:"%LOGFILE%"
if %ERRORLEVEL% geq 8 (
    call :LOG "[エラー] ファイルバックアップ失敗"
    set /a ERRORS+=1
) else (
    call :LOG "[成功] ファイルバックアップ完了"
)

rem === 2. DBバックアップ ===
if defined DB_NAME (
    call :LOG "[STEP 2] DBバックアップ開始"
    "%MYSQL_BIN%\mysqldump" -h %DB_HOST% -P %DB_PORT% -u %DB_USER% --single-transaction %DB_NAME% > "%DEST%\%DB_NAME%.sql"
    if !ERRORLEVEL! equ 0 (
        call :LOG "[成功] DBバックアップ完了"
    ) else (
        call :LOG "[エラー] DBバックアップ失敗"
        set /a ERRORS+=1
    )
)

rem === 3. 圧縮 ===
if exist %SEVEN_ZIP% (
    call :LOG "[STEP 3] 圧縮開始"
    %SEVEN_ZIP% a -t7z -mx=9 "%BACKUP_ROOT%\archives\%TODAY%.7z" "%DEST%\*"
    if !ERRORLEVEL! equ 0 (
        call :LOG "[成功] 圧縮完了"
        rd /s /q "%DEST%"
    ) else (
        call :LOG "[警告] 圧縮失敗(元ファイルは保持)"
    )
)

rem === 4. 世代管理 ===
call :LOG "[STEP 4] 世代管理実行"
set COUNT=0
for /f "delims=" %%d in ('dir /b /ad /o-n "%BACKUP_ROOT%" ^| findstr /r "^[0-9]"') do (
    set /a COUNT+=1
    if !COUNT! gtr %KEEP_GENERATIONS% (
        call :LOG "古い世代を削除: %%d"
        rd /s /q "%BACKUP_ROOT%\%%d"
    )
)

rem === 結果報告 ===
if %ERRORS% equ 0 (
    call :LOG "========== 全工程正常完了 =========="
) else (
    call :LOG "========== %ERRORS%件のエラーあり =========="
)

endlocal
exit /b %ERRORS%

rem === ログ関数 ===
:LOG
echo [%DATE% %TIME%] %~1
echo [%DATE% %TIME%] %~1 >> "%LOGFILE%"
goto :EOF

実行結果(ログ出力例)

[2026/03/05 02:00:01.23] ========== バックアップ開始 ==========
[2026/03/05 02:00:01.25] [STEP 1] ファイルバックアップ開始
[2026/03/05 02:01:30.45] [成功] ファイルバックアップ完了
[2026/03/05 02:01:30.50] [STEP 2] DBバックアップ開始
[2026/03/05 02:02:15.12] [成功] DBバックアップ完了
[2026/03/05 02:02:15.20] [STEP 3] 圧縮開始
[2026/03/05 02:03:45.80] [成功] 圧縮完了
[2026/03/05 02:03:46.00] [STEP 4] 世代管理実行
[2026/03/05 02:03:46.10] ========== 全工程正常完了 ==========

まとめ

やりたいこと 使うコマンド・機能
ファイルのコピー robocopy(推奨)/ xcopy
日付付きフォルダ %DATE:~0,4%%DATE:~5,2%%DATE:~8,2%
世代管理 for /f + dir /o-n で古い順に削除
ログ出力 /LOG オプション / リダイレクト(>>
エラーハンドリング %ERRORLEVEL%(robocopy は 8 以上がエラー)
自動実行 タスクスケジューラ / schtasks コマンド
DBバックアップ mysqldump / pg_dump
圧縮 7z.exe(7-Zip コマンドライン)
メール通知 PowerShell の SmtpClient を呼び出し
  • まずは最小構成(robocopy でファイルコピー)から始める
  • 動作確認ができたら日付フォルダ → 世代管理 → ログの順で機能を追加
  • 必要に応じて DB バックアップ・圧縮・メール通知 を組み込む
  • 最終的にタスクスケジューラで自動実行を設定して完全自動化を実現
  • 複雑なロジックが必要になったら PowerShell への移行を検討する