PowerShell

PowerShell でバックアップファイルを月別フォルダに自動整理するスクリプトを作った話|ログ付き・削除処理あり

PowerShell でバックアップファイルを月別フォルダに自動整理するスクリプトを作った話|ログ付き・削除処理ありアイキャッチ

はじめに

WordPress のバックアップ運用では、BackWPup や UpdraftPlus などのプラグインが生成する ZIP ファイルが日々蓄積されていきます。
しかし、そのまま放置しているとバックアップフォルダが膨れ上がり、どのファイルがいつのものなのか分かりづらくなる…という問題が発生します。

そこで今回は、バックアップファイルを月別フォルダに自動振り分けし、コピー後に元ファイルを削除、さらにログも月別で保管する PowerShell スクリプトを開発しました。

手作業での仕分けを完全に自動化でき、バックアップ管理がとても快適になります。

本記事では、スクリプトの仕組みとポイントを分かりやすく紹介します。

今回開発した PowerShell スクリプトの概要

今回作成したスクリプトは次の処理を自動で行います。

  • BackWPup / UpdraftPlus のバックアップ ZIP をコピー
  • ファイル名に含まれる日付から YYYYMM を抽出して月別フォルダに振り分け
  • コピーに成功したファイルのみ元フォルダから削除
  • ログファイルを生成し、最後にログを月別フォルダに整理して保管
  • バッチファイルから起動することで実行ポリシー制限も回避

バックアップ整理とログ管理を一度に解決できる仕組みです。

スクリプトが解決する課題

● バックアップファイルの肥大化と管理のしづらさ

ZIP が大量に生成されると整理が追いつきません。これを自動化します。

● 月別の分類作業が手間

ファイル名に日付が含まれているため、そこから年月を抽出し自動振り分けします。

● コピー後の削除でストレージを節約

コピー成功後にのみ削除され、失敗時は残る安全設計です。

● ログで処理内容が可視化される

コピー成功、削除結果、エラー内容がすべてログに残ります。

バックアップファイルの日付から年月を抽出する仕組み

対象ファイル名の例:

  • 2025-11-29_03-02-10_MYZIQUR207_FILE-DBDUMP-WPPLUGIN.zip
  • backup_2025-11-20-1602_yy_abc123-db.zip

どちらにも YYYY-MM-DD 形式の日付が含まれているため、

正規表現:(\d{4})-(\d{2})-(\d{2})

を使い、最初に見つかった日付から 202511 のような年月を取得します。

取得した年月を元にコピー先へ自動でフォルダを作成し、そこへファイルを移動します。

バックアップコピー & 削除処理の仕組み

コピー元は2つのプラグインに対応:

  • BackWPup
  • UpdraftPlus

それぞれについて次の処理を行います。

  1. コピー元フォルダのファイルを取得
  2. ファイル名から年月 (YYYYMM) を判定
  3. コピー先の \YYYYMM フォルダを作成
  4. コピー
  5. コピー成功時のみ元ファイルを削除
  6. 結果をログに記録

処理は try/catch で囲み、安全に動作するよう設計しています。

コピーに成功していないファイルは削除しないため安心です。

ログファイルを月別フォルダに整理する仕組み

スクリプト実行時にはログファイルを作成し、

[コンピュータ名]_backup_move_yyyymmdd_hhmmss.log

という形式で保存します。

処理が完了すると、このログを次のように整理します:

backup/log → re/log/YYYYMM/

ログも本体のバックアップ同様に年月ごとに保管されるため、後日トラブルシュートがしやすくなります。

バッチファイルからの実行方法(実行ポリシーの制限を回避)

PowerShell の実行ポリシーが Restricted の環境でも動作させやすいよう、バッチファイルから起動する方式を推奨しています。

run_backup.bat の例:

@echo off
powershell -ExecutionPolicy Bypass -File "C:\tools\bat\cron\Move-BackupFiles.ps1"

タスクスケジューラに登録して毎日自動実行することも可能です。

完成した PowerShell スクリプト全文

# バックアップファイルをコピーして元ファイルを削除するスクリプト
# ・コピー元/コピー先は下部の $backupSets で定義
# ・コピー結果はログに出力し、最後にログを別フォルダへコピーして元ログを削除

# =========================
# 設定エリア(必要に応じて変更)
# =========================

# バックアップコピー元/先(2セット)
$backupSets = @(
    @{
        Name        = 'BackWPup'
        SourceDir   = 'C:\Users\kuma\Dropbox\アプリ\BackWPup'
        TargetDir   = 'C:\Users\kuma\Box\backup\kumayy\BackWPup'
    },
    @{
        Name        = 'UpdraftPlus'
        SourceDir   = 'C:\Users\kuma\Dropbox\アプリ\UpdraftPlus.Com'
        TargetDir   = 'C:\Users\kuma\Box\backup\kumayy\UpdraftPlus'
    }
)

# ログの出力先とコピー先
$LogSourceDir = 'C:\tools\bat\cron\log'
$LogDestDir   = 'C:\Users\kuma\Box\backup\kumayy\log'

# ログファイル名
$ComputerName = $env:COMPUTERNAME
$TimeStamp    = Get-Date -Format 'yyyyMMdd_HHmmss'
$LogFileName  = "{0}_backup_move_{1}.log" -f $ComputerName, $TimeStamp
$LogPath      = Join-Path $LogSourceDir $LogFileName
$LogYearMonth = $TimeStamp.Substring(0, 6)   # 先頭6桁 = yyyymm

# =========================
# 関数定義
# =========================

# ログ出力用関数
function Write-Log {
    param(
        [string]$Message
    )
    $time = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $line = "[{0}] {1}" -f $time, $Message

    # 画面にも出す&ログファイルにも書く
    Write-Host $line
    Add-Content -Path $LogPath -Value $line
}

# ファイル名から「YYYYMM」を取得する関数
# 例: 2025-11-29_... -> 202511
#     backup_2025-11-20-1602_... -> 202511
function Get-YearMonthFromFileName {
    param(
        [string]$FileName
    )

    # ファイル名の中から「YYYY-MM-DD」を素直に探す
    $m = [regex]::Match($FileName, '(\d{4})-(\d{2})-(\d{2})')
    if ($m.Success) {
        $year  = $m.Groups[1].Value  # 2025
        $month = $m.Groups[2].Value  # 11
        return "$year$month"         # 202511
    }
    else {
        return $null
    }
}

# =========================
# メイン処理開始
# =========================

# ログ出力用フォルダを作成(なければ)
if (-not (Test-Path $LogSourceDir)) {
    New-Item -Path $LogSourceDir -ItemType Directory -Force | Out-Null
}

Write-Log "==== バックアップファイル移動処理 開始 ===="
Write-Log "ログファイル: $LogPath"

foreach ($set in $backupSets) {
    $name      = $set.Name
    $sourceDir = $set.SourceDir
    $targetDir = $set.TargetDir

    Write-Log "---- [$name] 開始 ----"
    Write-Log "コピー元: $sourceDir"
    Write-Log "コピー先: $targetDir"

    if (-not (Test-Path $sourceDir)) {
        Write-Log "警告:コピー元フォルダが存在しません。スキップします。 ($sourceDir)"
        continue
    }

    if (-not (Test-Path $targetDir)) {
        Write-Log "コピー先フォルダが存在しないため作成します。 ($targetDir)"
        New-Item -Path $targetDir -ItemType Directory -Force | Out-Null
    }

    # コピー元のファイル一覧を取得(全ファイル)
    $files = Get-ChildItem -Path $sourceDir -File -ErrorAction SilentlyContinue

    if (-not $files -or $files.Count -eq 0) {
        Write-Log "対象ファイルはありません。"
        continue
    }

    foreach ($file in $files) {
        $fileName = $file.Name
        $fullPath = $file.FullName

        # ファイル名から YYYYMM を取得
        $ym = Get-YearMonthFromFileName -FileName $fileName
        if (-not $ym) {
            Write-Log "エラー:ファイル名から年月(YYYYMM)を取得できないためスキップします。 ($fileName)"
            continue
        }

        # コピー先の年月フォルダ
        $destMonthDir = Join-Path $targetDir $ym

        if (-not (Test-Path $destMonthDir)) {
            Write-Log "コピー先年月フォルダを作成します。 ($destMonthDir)"
            New-Item -Path $destMonthDir -ItemType Directory -Force | Out-Null
        }

        $destPath = Join-Path $destMonthDir $fileName

        try {
            # ファイルコピー
            Copy-Item -LiteralPath $fullPath -Destination $destMonthDir -Force -ErrorAction Stop
            Write-Log "コピー成功: $fullPath -> $destPath"

            # コピー成功後のみ元ファイル削除
            Remove-Item -LiteralPath $fullPath -ErrorAction Stop
            Write-Log "元ファイル削除: $fullPath"
        }
        catch {
            Write-Log "エラー:$fullPath のコピーまたは削除中にエラーが発生しました -> $($_.Exception.Message)"
        }
    }

    Write-Log "---- [$name] 完了 ----"
}

Write-Log "==== バックアップファイル移動処理 完了 ===="

# =========================
# ログファイルのコピー&削除
# =========================

# ログコピー先の年月フォルダ(例: D:\data1\test\re\log\202512)
$LogDestMonthDir = Join-Path $LogDestDir $LogYearMonth

# ログコピー先フォルダ作成(なければ)
if (-not (Test-Path $LogDestMonthDir)) {
    Write-Host "ログコピー先フォルダが存在しないため作成します。 ($LogDestMonthDir)"
    New-Item -Path $LogDestMonthDir -ItemType Directory -Force | Out-Null
}

# 実際のコピー先パス
$LogDestPath = Join-Path $LogDestMonthDir $LogFileName

try {
    Write-Log "ログファイルをコピー先へコピーします。 ($LogDestPath)"
    Copy-Item -LiteralPath $LogPath -Destination $LogDestMonthDir -Force -ErrorAction Stop

    # この行はコピー済みのログにも残る
    Write-Log "ログファイルコピー完了。元ログを削除します。"

    # 元ログ削除
    Remove-Item -LiteralPath $LogPath -ErrorAction Stop
}
catch {
    # ここは元ログが削除できなかった場合などの画面用メッセージ
    Write-Host "ログファイルのコピーまたは削除中にエラーが発生しました: $($_.Exception.Message)"
}

# 終了メッセージ
Write-Host "すべての処理が終了しました。"

まとめ

今回紹介した PowerShell スクリプトにより、

  • バックアップファイルの月別整理
  • ストレージ圧迫の解消
  • ログ保存による可視化
  • 自動化による作業効率化

といったメリットを得ることができました。

バックアップ管理は「日付の整理」が最も手間なので、この部分を自動化するだけで運用は劇的に楽になります。

もし「別のプラグインにも対応したい」「メール通知を入れたい」など追加したい機能があれば、遠慮なく相談してください。

より便利な自動化スクリプトに仕上げていきましょう!

【改訂新版】Windows PowerShell ポケットリファレンス商品画像

【改訂新版】 Windows PowerShell ポケットリファレンス

PowerShell コマンドを “必要なときにすぐ引ける” 実用リファレンス。
日常の管理作業から自動化まで、ポイントを押さえたコンパクトな解説が魅力。
手元に置いておくとスクリプト作成のスピードが一気に上がります。

おすすめポイント:

  • コマンドや構文がサッと探せて実務で便利
  • 細かい機能やオプションまで網羅されている
  • スクリプト作成中の「詰まり」をすぐ解消できる

Rakuten

Amazon

Yahoo!ショッピング

  • この記事を書いた人
  • 最新記事

かじ

くまyyの管理人:かじ。 社内SEとして13年勤務、システム企画・開発をしているIT屋さん。 ガジェット好きなので最新ガジェットを追いかけるのが好き。 プログラミングなど自分の知識と経験をいろんな人に役立ってもらえるように記事を更新します!

-PowerShell
-,