IT管理のマメ知識

ITについて個人の感想をアウトプットしているブログ

(powershell)xcopyコマンドでバックアップ世代管理

[powershell] xcopyコマンドでバックアップ

スクリプトの目的

  • このスクリプトは、Windows環境でバックアップ世代管理を行うことができるPowershellスクリプトです。
  • 重要なデータが含まれるフォルダを、ネットワーク接続された別コンピューターやNas等のデバイスにバックアップする際に使用することができます。もちろん、同じPCにUSB接続されたポータブルハードディスクでも構いません。

バックアップ対象のデータサイズが大きい場合の注意点

  • バックアップ方法は、対象フォルダ全体のレプリケーションですが、世代管理によりフォルダ分けされます。
  • そのためバックアップ世代数分のデータ容量が必要となります。バックアップ対象のデータ量が多く、また保持しておくたいバックアップ世代数が多いほど、多くのディスク容量を消費することになることに注意が必要です。
  • さらに、バックアップ対象のデータ量が多くなるにつれて、xcopyコマンド実行にかかる時間と、古くなったバックアップ世代のデータを削除するためにかかる時間が長くなりますので、所要時間についても考慮が必要となります。

概要

  • バックアップ処理は、xcopyコマンドを呼び出して実行しています。xcopyコマンドは、コピー手段としては信頼性が高いとされています。
  • バックアップ世代管理は、powershellが備えるコマンドにより実行しています。

  • どのようにバックアップが行われるか、下記の"サンプルコードの環境例", "実行ログのサンプル"を参照してください。

  • 実行環境に合わせたパラメータ設定方法を行ってください。
  • スクリプトVisual Studio Code上で作成しました。実行環境に合わせたパラメータ設定を行うために、ps1ファイルを編集して保存する場合は、文字エンコーディングを「utf8 With BOM」としてください。エンコードが異なると、パス名に含まれる日本語が文字化けしたり、うまく動作しなかったりするようです。

スクリプトに関係する外部サイト

実行環境に合わせたパラメータ設定方法

  • ps1ファイル内の、以下の変数を実行環境に合わせて書き換えてください。
  $FromPath = "バックアップ対象フォルダのパス名"  
  $DestPath = "バックアップ先フォルダのパス名" ※末尾には\を付けてください  
  $TranscriptPath = "実行ログの出力先パス名"   ※ファイル名を含む完全パス名
[バックアップ対象フォルダ]
$FromPath = "バックアップ対象フォルダのパス名"  

[バックアップ先フォルダ(世代フォルダの作成先)]
$DestPath = "バックアップ先フォルダのパス名\"  
[例]
$FromPath  = "C:\Folder1"              
$DestPath  = "C:\Folder1_backup\" 
 
実行時、[$DestPath+日付時刻文字列]でバックアップ先フォルダが作成されます。
 (例えば 2022年3月5日14時01分02秒に実行した場合)
  $DestPath  ="C:\Folder1_backup\20220304_140102\" フォルダ内にバックアップが作成されます。

[実行ログの出力先パス名]
$TranscriptPath = "フルパス"
[例]
# $TranscriptPath = "C:\Folder1\backup_xcopy_datetime.log"

サンプルコードの環境例

  • サンプルコードは、以下のフォルダ階層を想定したものとなっています。
[バックアップ対象のフォルダ]
C:\FOLDER1

[バックアップ世代フォルダ内に作成される世代フォルダ]
C:\FOLDER1_BACKUP
└[yyyyMMdd-HHmmss]フォルダ ※世代数分が保持されます。
  • バックアップ世代数を5世代とした場合、以下の例のようにバックアップ先フォルダ内には、常に直近の5世代分(5フォルダ)が維持されます。
  • 以下の状態から新たに当スクリプトを実行すると、新たに[yyyyMMdd-HHmmss]フォルダ(実行した日時分秒のフォルダ)が作成され、新たに保持すべき世代数としてカウンタとされます。そのため[20220306-101721]フォルダは6世代目となり保持対象を超え、フォルダごと削除されます。
[バックアップ世代フォルダ内に作成される世代フォルダ]
C:\FOLDER1_BACKUP
├─20220306-101721
├─20220306-101755
├─20220306-101820
├─20220306-101905
└─20220306-101931

実行ログのサンプル

  • PowerShellのトランスクリプトにより、以下のようなログファイルが出力されます。
  • 実環境において、ログファイルから読み取れる大切な内容は以下のとおりです。
    • XCOPYコマンドの終了コードと、その説明(Microsoftが公開しているxcopyコマンドの戻り値の説明文です。)
    • 各バックアップ世代フォルダの削除と維持の状態

**********************
Windows PowerShell トランスクリプト開始
**********************
トランスクリプトが開始されました。出力ファイル: C:\backup_xcopy_datetime.log
.
FromPath  = C:\Folder1
DestPath2 = C:\Folder1_backup\20220306-101308\
.


    ディレクトリ: C:\Folder1_backup


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2022/03/06     10:13                20220306-101308
.
XCOPYコマンドを開始します
.

.
XCOPYコマンドが終了しました
.
xcopy終了コード=0:ファイルはエラーなしでコピーされました。
.
バックアップ世代管理の処理を開始
.
バックアップ先ベースフォルダ名:C:\Folder1_backup\
 バックアップのサブフォルダの総数:6
 保持する世代数:5
 削除されるフォルダ数:1
1 : 古いバックアップ世代のため削除 : 20220306-101004
2 : 保持対象:20220306-101006
3 : 保持対象:20220306-101146
4 : 保持対象:20220306-101220
5 : 保持対象:20220306-101242
6 : 保持対象:20220306-101308
.
バックアップ世代管理の処理が終了しました
.
**********************
Windows PowerShell トランスクリプト終了
**********************

ソースコード

# --------------------------------------------------------------------------------------------------------------------
# $FromPath = "バックアップ対象フォルダのパス名"  
# $DestPath = "バックアップ先フォルダのパス名\"  
# [例]
# $FromPath  = "C:\Folder1"              ※末尾には\を付けないでください。
# $DestPath  = "C:\Folder1_backup"  ※末尾に\を付けてください。
# 
# 実行時、[$DestPath+日付時刻文字列]でバックアップ先フォルダが作成されます。
# (例えば 2022年3月5日14時01分02秒に実行した場合)
#  $DestPath  ="C:\Folder1_backup\20220304_140102\" フォルダ内にバックアップが作成されます。
# --------------------------------------------------------------------------------------------------------------------
# ▼ 実行環境に合わせて書き換えてください。
$FromPath = "C:\Folder1"
$DestPath = "C:\Folder1_backup\" 
$BackupHistoryCount = 5



# --------------------------------------------------------------------------------------------------------------------
# $TranscriptPath       = "D:\バックアップXCOPY\backup_xcopy_datetime.log"
# ログファイルの出力先パス名を指定してください。
# --------------------------------------------------------------------------------------------------------------------
# ▼ 実行環境に合わせて書き換えてください。
$TranscriptPath       = "C:\Folder1\Xcopy_with_HistoryManagement.log"


# --------------------------------------------------------------------------------------------------------------------
# 以下は実行コードです。変更しないでください。  
# --------------------------------------------------------------------------------------------------------------------
# PowerShellログ出力の開始
Start-Transcript $TranscriptPath

# 日時分秒別のパスを作成
$ymdhms=Get-Date -Format "yyyyMMdd-HHmmss"
$DestPath2 = $DestPath + $ymdhms  + "\"

ECHO .
ECHO "FromPath  = $FromPath"
ECHO "DestPath2 = $DestPath2"
ECHO .

# バックアップ先フォルダを作成
New-Item ( $DestPath2 ) -ItemType Directory

ECHO .
ECHO "XCOPYコマンドを開始します"
ECHO .

XCOPY $FromPath $DestPath2 /S /Y /E /C /H 

# エラー検査
$XcopyExitCode=$LastExitCode

ECHO .
ECHO "XCOPYコマンドが終了しました"
ECHO .

if( ( $XcopyExitCode ) -eq 0 ) { ECHO xcopy終了コード=0:ファイルはエラーなしでコピーされました。               }
if( ( $XcopyExitCode ) -eq 1 ) { ECHO xcopy終了コード=1:コピーするファイルが見つかりませんでした。             }
if( ( $XcopyExitCode ) -eq 2 ) { ECHO xcopy終了コード=2:ユーザーが Ctrl + C キーを押して xcopy を終了しました。}
if( ( $XcopyExitCode ) -eq 4 ) { ECHO xcopy終了コード=4:初期化エラーが発生しました。 メモリまたはディスク領域が不足しているか、コマンド ラインに無効なドライブ名または無効な構文が入力されました。}
if( ( $XcopyExitCode ) -eq 5 ) { ECHO xcopy終了コード=5:ディスク書き込みエラーが発生しました。                 }


ECHO .
ECHO "バックアップ世代管理の処理を開始"
ECHO .

# バックアップ世代管理
[System.IO.DirectoryInfo[]] $DestPath_SubFolders = dir $DestPath  -Directory

$DestPath_SubFolders_Count         = $DestPath_SubFolders.Count
$DestPath_SubFolders_EraseCount = $DestPath_SubFolders.Count - $BackupHistoryCount

echo "バックアップ先ベースフォルダ名:$DestPath"
echo " バックアップのサブフォルダの総数:$DestPath_SubFolders_Count"
echo " 保持する世代数:$BackupHistoryCount"
echo " 削除されるフォルダ数:$DestPath_SubFolders_EraseCount"

$cnt = 0
foreach ($item in $DestPath_SubFolders) {
    $cnt = $cnt + 1
    if( ( $cnt -le $DestPath_SubFolders_EraseCount ) -eq "true"  ){ 
        ECHO "$cnt : 古いバックアップ世代のため削除 : $item"

        $eraseFullPath = $DestPath + $item
        Remove-Item -Path $eraseFullPath -Recurse -Force
    } else { 
        ECHO "$cnt : 保持対象:$item" 
    }
}

ECHO .
ECHO "バックアップ世代管理の処理が終了しました"
ECHO .

# PowerShellログ出力の終了
Stop-Transcript