◇WindowsのバッチファイルでRobocopyによるバックアップを簡単に使う

日頃使っているバッチファイルです。
Robocopyが非常に優秀なのはご存じのとおりです。
当然、大勢の方がラッパーを作っていますので今更感はありますがサクっと使えるものが見当たらず自作したものです。
今回はQiitaに掲載できるよう見やすいように修正、トーストに終了通知を加えたりしています。
また改良中に紹介していないテクニックがあったので抜粋、再編集して掲載しました。

2022/08/20 Robocopyの終了結果によるメッセージを追加しました。


- [◇ドライブかファイルかフォルダかを判別する][]
- [◇カレントフォルダ名を取得する][]


## ◇Robocopyによるバックアップを簡単に行うバッチ
〇実際の操作イメージ
![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588934/c2fe41e8-7dfc-1c6b-6a42-b21509854729.gif)


〇事前準備

- コピー元をDrive Cにあるフォルダ「Target」を親とする配下のフォルダすべて。
- コピー先をDrive Dにあるフォルダ「Backup」とします。

コピー元の「Target」フォルダにバッチファイル「`@BackupToDragDropDrive.bat`」を保存しておきます。

```
コピー実行前のツリー構造
├─Drive C
│  └─Source
│      └─Target
│          ├─Folder A
│          └─@BackupToDragDropDrive.bat
└─Drive D
    └─Backup
```

〇コピーを実行する

1. バッチファイル「`@BackupToDragDropDrive.bat`」にコピー先の「Backup」フォルダをドラッグアンドドロップします。
1. 「Target」フォルダが「Backup」フォルダの下に`同期で`コピーされます。

```
コピー実行後のツリー構造
├─Drive C
│  └─Source
│      └─Target
│          ├─Folder A
│          └─@BackupToDragDropDrive.bat
└─Drive D
    └─Backup
        └─Target
            ├─Folder A
            └─@BackupToDragDropDrive.bat
```

数回使ってみれば、それほど迷うことなく使えると思います。



<details><summary>Robocopyによるバックアップを簡単に使うバッチファイル</summary>

```bat:@BackupToDragDropDrive.bat
@echo off


:: 遅延展開 バグの原因になる場合があるので注意;
setlocal enabledelayedexpansion


:: エスケープシーケンスを利用;
for /f "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (set ESC=%%b)


:: バッチファイルのShift-jis対策;
::chcp 65001>nul


:: コピーするフォルダ名を設定;
set SourcePath=%~dp0
set SourcePath=%SourcePath:~0,-1%


:: 現在のフォルダ名を取り出しでコピー先を設定;
call :GetCurrenrFolderName "%SourcePath%"
goto :EndGetCurrenrFolderName
:GetCurrenrFolderName
set CurrentFolderName=%~n1
exit /b
:EndGetCurrenrFolderName


:: コピー先がフォルダかチェックしてコピー先を変更;
set DestinationPathATTR=%~a1
set DestinationPathATTR=%DestinationPathATTR:~0,1%
set DestinationPath=%~dp1%CurrentFolderName%
if /i "%DestinationPathATTR%" equ "d" if /i "%~n1" neq "" (
  set DestinationPath=%~dpn1\%CurrentFolderName%
)


:: 実行確認;
set MessageTitle=Robocopy Backup
set Message1=コピー元：%SourcePath% から
set Message2=コピー先：%DestinationPath% へ
set Message3=更新バックアップをします。
set Yes=6
echo %cmdcmdline% | find /i "%~f0">NUL
if %errorlevel% equ 0 (title %MessageTitle% ^(%DATE% - %TIME%^))
echo.
echo %ESC%[44m◆◆◆%MessageTitle%◆◆◆%ESC%[0m
echo.
echo %Message1%
echo.
echo %Message2%
echo.
echo %Message3%
echo.


:: ウインドウを表示して問い合わせ;
powershell -Command "Add-Type -AssemblyName System.Windows.Forms;$result = [System.Windows.Forms.MessageBox]::Show(\"%Message1%`n%Message2%`n%Message3%\", '%MessageTitle%', 'YesNo', 'Asterisk');exit $result;"
if "%ERRORLEVEL%" neq "%Yes%" (goto :EndProcess)


:: RoboCopy Backup;
robocopy "%SourcePath%" "%DestinationPath%" /mir /dcopy:dat
set RoboCopyERRORLEVEL=%ERRORLEVEL%


:: 終了メッセージの設定と表示;
set EndMsg=RoboCopy バックアップ
if "%ERRORLEVEL%" equ "0" (
  set ELMsg=ファイルはコピーされませんでした。
  set ELColor=%ESC%[43;30m
  goto :ResultMessage
)
if "%ERRORLEVEL%" equ "1" (
  set ELMsg=正常にコピーされました。
  set ELColor=%ESC%[42;97m
  goto :ResultMessage
)
if "%ERRORLEVEL%" equ "2" (
  set ELMsg=ファイルはコピーされませんでした。
  set ELColor=%ESC%[43;30m
  goto :ResultMessage
)
if "%ERRORLEVEL%" equ "3" (
  set ELMsg=一部のファイルがコピーされました。
  set ELColor=%ESC%[43;30m
  goto :ResultMessage
)

if "%ERRORLEVEL%" equ "5" (
  set ELMsg=一部のファイルがコピーされました。
  set ELColor=%ESC%[43;30m
  goto :ResultMessage
)
if "%ERRORLEVEL%" equ "6" (
  set ELMsg=ファイルはコピーされませんでした。
  set ELColor=%ESC%[43;30m
  goto :ResultMessage
)
set ELMsg=エラーが発生しています。
set ELColor=%ESC%[41;97m
:ResultMessage
echo.
echo %ESC%[1;4m%EndMsg%%ESC%[0m
echo.
echo %ELColor%%ELMsg%%ESC%[0m
echo.
echo %ESC%[1mErrorlevel = [%ERRORLEVEL%]%ESC%[0m
echo.
echo %Message1%
echo %Message2%
echo.


:: Toastによる終了通知;
set ToastMsg=\"%EndMsg%`n%Message1%`n%Message2%`n`n%ELMsg%`nErrorlevel = [%ERRORLEVEL%]`n\"
PowerShell.exe ^&{$m=%ToastMsg%;$a='%comspec%';$t=[Windows.UI.Notifications.ToastNotificationManager,Windows.UI.Notifications,ContentType=WindowsRuntime]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType,Windows.UI.Notifications,ContentType=WindowsRuntime]::ToastText01);$t.GetElementsByTagName('text').Item(0).InnerText=$m;[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($a).Show($t);}


:: 終了お知らせ音;
PowerShell ^&{Start-Sleep -milliseconds 100;[Console]::Beep(524,500);[Console]::Beep(660,500);[Console]::Beep(784,500);[Console]::Beep(1046,900);}


:: 終了処理を起動条件により分岐（エクスプローラーから起動されていた場合は選択処理）;
:EndProcess
echo %CMDCMDLINE%|find /i "%~f0">NUL
if "%ERRORLEVEL%" neq "0" (goto :eof)
choice /t 10 /c qa /d q /m "10秒待機します。即閉じる場合はQ、待機はAを押してください。"
if "%ERRORLEVEL%" equ "2" (
  echo %ESC%[1A%ESC%[2K%ESC%[1A
  pause
)
goto :eof
```
</details>

[◇カレントフォルダ名を取得する]:https://qiita.com/aromatibus/items/8075514b134b2f0424b7
[◇ドライブかファイルかフォルダかを判別する]:https://qiita.com/aromatibus/items/465ab903059a4658ffc4


# おわりに

他にも「[⧉Windowsのバッチファイルのテクニックをご紹介します][]」にてご紹介させて頂いております。
お時間ありましたら覗いてみてください
お粗末様でした。

https://github.com/Aromatibus/

[⧉Windowsのバッチファイルのテクニックをご紹介します]: https://qiita.com/aromatibus/items/12fa4775f38c9889a686