ローカルフォルダ(Dドライブ)のデータを自宅NASにバックアップしたい
Cドライブはシステムイメージバックアップを取っているけど、そういえばDドライブに溜め込んだデータはバックアップ設定していないなーと思ったので自宅のNASにデータバックアップをすることにした。
Dドライブ丸ごとコピーしてNASにペーストしても良かったのだが、それなりにちょこちょこデータが更新されるので毎回コピー・ペーストするのもカッコ悪いなと思い、PowerShellとRobocopyを利用してバックアップスクリプトを作ることにした。
うちのNASはID/PASSをアクセス時に要求するので、robocopy実行前にNASにアクセスするようにした。
また、robocopy結果をログに残す仕様にすることにした。
さらに、一々管理者権限で実行を指定するのは面倒なので、スクリプト内で管理者として実行しているか確認し、管理者として実行されていない場合は管理者として実行するように促す形にした。
搭載機能
- 指定したコピー元($srcFolder)から指定したコピー先($dstFolder)へrobocopyを実施する。
今回は、コピー元を「Dドライブ」、コピー先を「\192.168.1.253\backup\Dドライブ」とする。(適宜修正してください) - コピー先のNASに対してrobocopy実行前にユーザーID/PASSで資格情報を取得しておく。
本スクリプトではユーザー名を「backupper」、PASSを「backupperpass」としておく。(適宜修正してください) - robocopyのオプションは以下とする。
/MIR /DCOPY:DAT /COPY:DAT /IT /B /log+:"$logFile" /np /R:3 /W:3
/MIRはコピー元とコピー先を同じ状態になるようにするオプションである。
/DCOPY:DATはディレクトリにコピーする情報を指定するオプションである。
D(データ)、A(属性)、T(タイムスタンプ)をコピーする。
/COPY:DATはファイルにコピーする情報を指定するオプションである。
D(データ)、A(属性)、T(タイムスタンプ)をコピーする。
なお、/COPYALLは恐らく以下のようなエラーとなる。
注意: セキュリティがコピーされない可能性があります - コピー元で固定 ACL がサポートされていない可能性があります。
エラー 1314 (0x00000522) NTFS セキュリティをコピー先ディレクトリにコピーしています \\192.168.1.253\backup\Dドライブ\ クライアントは要求された特権を保有していません。
これは、/COPYALLだとセキュリティ情報等までもコピー対象にしてしまうので、ローカルと権限の管理管轄が異なるNASではコピーしようがないためと思われる。同一ドメインで管理されていれば問題なく通るかもしれない(未検証)。
/ITはファイル属性だけが異なるファイル(Tweaked)もコピー対象に含めるオプションである。
/Bはバックアップモードでの実行を指定するオプションである。これは対象ファイルへのアクセス権がなかったとしてもファイルコピーできるようになるオプションである。(なので本スクリプトの実行は管理者権限を持つユーザーが対象となる)
/log+:"$logFile"は$logFileにログを出力させるオプションである。
/npはコピーの完了率を表示させないオプションである。これはログ出力時にログが完了率だらけで読めなくなるのを防ぐためである。
/R:3は失敗したコピーに対する再試行回数を3に指定するものである。
/Rは既定値が1,000,000であり、コピー時間が無駄に増大するだけなので最低限の回数に変更する。
/W:3は再試行と再試行の間の待機時間を3秒間に指定するものである。
/Wは既定値が30秒であり、/Rと合わせてコピー時間が無駄に増大するだけなので最低限の秒数に変更する。 - 管理者権限で実行をされているかを確認し、されていない場合は管理者権限で再実行する。
- robocopyの実行結果をログ出力し、ログ保存用のフォルダに保存する。
$logFolderでログフォルダパスを指定し、$logFileでログのファイル名を指定する。
本スクリプトではログフォルダパスを「\192.168.1.253\backup\バックアップ用ツール\Dドライブロボコピー\log」とする。(適宜修正してください)
なお、ログフォルダは予め作成しておく必要あり。
ファイル名はyyyy-mm-dd_datacopy.logとなるようにする。 - 指定された日数よりも古いログファイルがあった場合、自動でログを削除するようにする。
本スクリプトでは93日(約3ヶ月間)より古いログは削除する仕様とする。
コード
絶対改善余地があるけどこんな感じ。
青字アンダーライン部分は搭載機能に記載した適宜修正部分のため、自身の環境に応じて書き換えされたし。
# PowerShellスクリプト
# 現在のスクリプトが管理者権限で実行されているか確認
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
# 管理者として実行されていない場合は再起動
if (-not $isAdmin) {
Write-Host "管理者として再実行しています..."
Start-Sleep -Seconds 2
Start-Process powershell.exe -ArgumentList ("-NoProfile -ExecutionPolicy Bypass -File `"" + $MyInvocation.MyCommand.Path + "`"") -Verb RunAs
Exit
}
# ネットワーク共有へのアクセス情報
$networkSharePath = "\\192.168.1.253\backup"
$networkCredential = New-Object System.Management.Automation.PSCredential -ArgumentList @("backupper", (ConvertTo-SecureString -String "backupperpass" -AsPlainText -Force))
# ソースフォルダと宛先フォルダの指定
$srcFolder = "D:"
$dstFolder = Join-Path $networkSharePath "Dドライブ"
# ログフォルダとログファイルの指定
$logFolder = "\\192.168.1.253\backup\バックアップ用ツール\Dドライブロボコピー\log"
$logFile = Join-Path $logFolder "$((Get-Date).ToString('yyyy-MM-dd'))_datacopy.log"
# Robocopyを使用してフォルダのコピー
robocopy $srcFolder $dstFolder /MIR /DCOPY:DAT /COPY:DAT /IT /B /log+:"$logFile" /np /R:3 /W:3
# 指定された日数よりも古いログファイルを削除
Get-ChildItem -Path $logFolder -Filter "*.log" | Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-93) } | ForEach-Object { Remove-Item $_.FullName -Force }
# スクリプトの実行が完了したことを表示
Write-Host "スクリプトの実行が完了しました。"
実行イメージ
注意点と補足
- PowerShellが実行可能な環境である必要があります。
改版履歴
2024/02/08 初版公開
コメント