システムエンジニアXの「プログラミング以外」の話 50代会社員SEのお仕事・副業・システム運用の経験談

PowerShellで日付「yyyyMMdd」を取得する鉄板構文とログ世代管理

公開:

※本記事には広告を含みます。

はじめに

夜間バッチや定期メンテナンス用のPowerShellスクリプトを作成する際、ログファイル名に「backup_20260901.log」のような日付(yyyyMMdd)を付与したい場面は頻繁にあります。

私も過去に、古いバッチファイル(%DATE:~0,4%...)の感覚で日付処理を書いたり、書式指定の大文字・小文字を間違えたりした結果、実行する時刻によってログファイル名が変わり、世代管理スクリプトが古いログを消し損ねてディスク容量を逼迫させた苦い経験があります。

PowerShellにおける日付フォーマットとログローテーションは、基本構文と「ハマりやすい罠」さえ押さえておけば、OSの言語設定や環境に依存しない堅牢な自動化スクリプトをわずか数行で実装できます。

この記事では、PowerShell 5.1およびPowerShell 7の両環境で確実に動作する「yyyyMMdd」取得の鉄板構文から、最新N世代のみを残して古いログを自動削除する実践スクリプトまで徹底解説します。

読み終えるころには、コピペしてすぐに現場の定期実行タスクへ組み込める、安全なログ管理テンプレートを手に入れられます。

この記事の要点

  • 日付文字列の取得は Get-Date -Format "yyyyMMdd" または (Get-Date).ToString("yyyyMMdd") を使うのが最も確実でロケールに依存しない
  • 書式指定では「月(Month)」が大文字の MM、「分(minute)」が小文字の mm であり、混同するとファイル名が毎分変わる事故につながる
  • ログの世代管理は Get-ChildItem | Sort-Object LastWriteTime -Descending | Select-Object -Skip N | Remove-Item のパイプライン構文で安全に自動化できる
項目 動作確認・検証環境
検証年月 2026年9月
対象OS Windows 11 Pro 23H2・24H2 / Windows Server 2022
対象バージョン Windows PowerShell 5.1 / PowerShell 7.4
必要権限 一般ユーザー権限(ログ保存先フォルダへの読み書き権限)

結論:PowerShellで「yyyyMMdd」を取得する3つの鉄板構文

結論からお伝えすると、PowerShellで現在日付を「yyyyMMdd」形式の文字列として取得するには、Get-Date -Format "yyyyMMdd" を使用するのが最もシンプルで可読性が高い推奨構文 です。

用途やスクリプトの書き方に応じて、以下の3つの構文を使い分けます。

1. 基本構文:Get-Date -Format "yyyyMMdd"

コマンドレットのパラメータとしてフォーマットを指定する、PowerShellらしい標準的な書き方です。

# 実行日(例:2026年9月15日)を8桁の文字列で取得
$today = Get-Date -Format "yyyyMMdd"
Write-Output $today
# 出力結果: 20260915

戻り値は文字列型([string])になるため、そのままファイルパスや変数展開に利用できます。

2. メソッド構文:(Get-Date).ToString("yyyyMMdd")

.NETの DateTime オブジェクトが持つ ToString() メソッドを呼び出す書き方です。前日や翌日など、日付計算(AddDays)と組み合わせる場合に威力を発揮します。

# 昨日の日付を「yyyyMMdd」形式で取得
$yesterday = (Get-Date).AddDays(-1).ToString("yyyyMMdd")

# 30日前の日付を取得
$thirtyDaysAgo = (Get-Date).AddDays(-30).ToString("yyyyMMdd")

3. 構文パターンと書式指定子の比較表

現場のログ出力やタイムスタンプ記録でよく使うフォーマット指定子の一覧は以下の通りです。

目的・出力イメージ PowerShell構文例 出力結果の例 主な用途
日付のみ(8桁) Get-Date -Format "yyyyMMdd" 20260915 日次ログファイル名、日次バックアップフォルダ名
日時(秒まで・14桁) Get-Date -Format "yyyyMMdd_HHmmss" 20260915_143005 1日に複数回実行するスクリプトのログファイル名
ログ行内タイムスタンプ Get-Date -Format "yyyy-MM-dd HH:mm:ss" 2026-09-15 14:30:05 ログファイル内部に記録するイベント発生時刻
前日の日付(8桁) (Get-Date).AddDays(-1).ToString("yyyyMMdd") 20260914 前日分ログの集計・アーカイブ処理

表の通り、24時間表記の「時」には大文字の HH を使用します。小文字の hh にすると12時間表記(午前1時と午後1時がどちらも 01)になるため注意してください。


現場でハマる日付フォーマット3つの落とし穴

日付取得は非常にシンプルな処理ですが、本番運用のスクリプトで思わぬバグを引き起こす代表的な落とし穴が3つあります。

落とし穴1:大文字「MM(月)」と小文字「mm(分)」の取り違え

最も多いミスが、すべて小文字で yyyymmdd と書いてしまうケースです。

PowerShell(.NET)のカスタム日時書式指定文字列では、大文字と小文字が厳密に区別されます。

# 【NG例】小文字の「mm」は「分(minute)」を意味する
# 2026年9月15日 14時45分に実行した場合
Get-Date -Format "yyyymmdd"
# 出力結果: 20264515 (「09月」ではなく「45分」が入ってしまう!)

# 【OK例】大文字の「MM」で「月(Month)」を指定する
Get-Date -Format "yyyyMMdd"
# 出力結果: 20260915

小文字の mm を使うと、実行した時刻の「分」が月として埋め込まれ、20264515 のような存在しない日付のログファイルが生成されてしまいます。必ず「月は大文字の MM」と徹底してください。

落とし穴2:-Format と -UFormat の混同

Get-Date には、UNIXの strftime に似た書式を使う -UFormat パラメータも存在します。

  • -Format:.NET標準書式(yyyyMMdd)を使用
  • -UFormat:UNIX形式(%Y%m%d)を使用

-UFormat はPowerShell 5.1とPowerShell 7の間で一部の書式指定子(%s や曜日表記など)の挙動に差異があります。Windows運用の現場では、バージョン間の互換性が高くC#等とも共通している -Format(または .ToString())に統一する のが鉄則です。

落とし穴3:文字列化した日付と DateTime 型の比較ミス

Get-Date -Format "yyyyMMdd" で取得した変数は、日付型([DateTime])ではなく単なる文字列([string])です。そのため、変換後の変数に対して .AddDays(-7) などのメソッドを呼び出すと以下のエラーが発生します。

MethodInvocationException: Method invocation failed because [System.String] does not contain a method named 'AddDays'.

日付の加算・減算や経過日数の比較を行う場合は、[DateTime] 型のまま計算を済ませ、ファイル名や画面に出力する最後の段階で .ToString("yyyyMMdd") を使って文字列化してください。


【実践】日付付きログ出力と世代管理(ローテーション)の自動化スクリプト

ここからは、取得した yyyyMMdd を使って日付付きログファイルを出力し、古いログを自動的に削除(ローテーション)する実用的なスクリプトを解説します。

1. 最新N世代を残して古いログを削除する鉄板ワンライナー

「フォルダ内のログファイルを更新日時の新しい順に並べ、最新10件(10世代)をスキップし、残った11件目以降を削除する」という処理は、以下のパイプライン1行で実現できます。

# 最新10世代を残し、11世代目以降の古いログファイルを削除(確認用の -WhatIf 付き)
Get-ChildItem -Path "C:\Logs\Backup_*.log" -File |
    Sort-Object LastWriteTime -Descending |
    Select-Object -Skip 10 |
    Remove-Item -Force -WhatIf

各コマンドレットの役割は以下の通りです。

  1. Get-ChildItem -Path "C:\Logs\Backup_*.log" -File:対象のログファイルのみを取得(フォルダを誤って消さないよう -File を明示)。
  2. Sort-Object LastWriteTime -Descending:最終更新日時(LastWriteTime)の降順(新しい順)にソート。ファイル名に yyyyMMdd が入っている場合は Sort-Object Name -Descending でも同様に新しい順になります。
  3. Select-Object -Skip 10:先頭から10件(最新の10ファイル)を除外し、11件目以降の古いファイルだけを後続へ渡す。
  4. Remove-Item -Force -WhatIf:渡された古いファイルを削除。初回テスト時は必ず -WhatIf を付けて、削除対象が正しいか目視確認します。

2. 「世代数ベース」と「保存日数ベース」の使い分け

ログローテーションには「最新Nファイルを残す(世代数ベース)」と「N日以上前のファイルを消す(保存日数ベース)」の2つの設計アプローチがあります。

ローテーション方式 判定基準 メリット デメリット・注意点
世代数ベース(Select -Skip N) ファイルの個数 タスクが数日間停止していても、直近N回分の実行ログが確実に残る 1日に何度も手動実行すると、数日分のログが押し出されて消える
保存日数ベース(AddDays(-N)) 最終更新日時 「過去30日分を保管する」といった監査要件・規程に合わせやすい バッチが30日間停止していた場合、過去のログが全滅するリスクがある

日次で1回動く定期バッチであれば「世代数ベース」が安全であり、監査証跡として保管期間が決まっている場合は「保存日数ベース」または両方の併用を選択します。

3. コピペで使える!ログ出力+世代管理の完全テンプレート

以下は、現場のタスクスケジューラにそのまま登録して使える「日付付きログ出力+世代管理」の統合テンプレートです。

# ==============================================================================
# スクリプト名: Invoke-DailyJobWithLogRotation.ps1
# 概要        : 日付付きログ(yyyyMMdd)の出力と、世代管理(最新14世代保持)を行う
# 実行権限    : 一般ユーザーまたはタスク実行アカウント(C:\Logsへの書込権限が必要)
# ==============================================================================
$ErrorActionPreference = "Stop"

# 1. 設定値の定義
$LogDir      = "C:\Logs\DailyBatch"
$LogPrefix   = "DailyBatch_"
$KeepCount   = 14  # 保持するログの世代数

# 2. ログ保存先フォルダの作成(存在しない場合)
if (-not (Test-Path -Path $LogDir)) {
    New-Item -Path $LogDir -ItemType Directory -Force | Out-Null
}

# 3. 当日の日付文字列(yyyyMMdd)を取得してログファイルパスを生成
$DateStr     = Get-Date -Format "yyyyMMdd"
$LogFilePath = Join-Path -Path $LogDir -ChildPath "${LogPrefix}${DateStr}.log"

# ログ出力用ヘルパー関数
function Write-BatchLog {
    param([string]$Message, [string]$Level = "INFO")
    $TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $LogLine   = "[$TimeStamp] [$Level] $Message"
    Write-Output $LogLine
    Add-Content -Path $LogFilePath -Value $LogLine -Encoding UTF8
}

try {
    Write-BatchLog "=== 日次バッチ処理を開始します ==="

    # --- ここに本来の業務処理(ファイルバックアップやデータ連携など)を記述 ---
    Write-BatchLog "業務処理を実行中です..."
    # ----------------------------------------------------------------------

    # 4. ログファイルの世代管理(最新 $KeepCount 件を残して古いログを削除)
    Write-BatchLog "ログローテーションを開始します(保持世代数: $KeepCount)"
    $OldLogs = Get-ChildItem -Path $LogDir -Filter "${LogPrefix}*.log" -File |
               Sort-Object LastWriteTime -Descending |
               Select-Object -Skip $KeepCount

    foreach ($File in $OldLogs) {
        Remove-Item -Path $File.FullName -Force
        Write-BatchLog "古いログファイルを削除しました: $($File.Name)"
    }

    Write-BatchLog "=== 日次バッチ処理が正常に完了しました ==="
}
catch {
    Write-BatchLog "エラーが発生しました: $($_.Exception.Message)" -Level "ERROR"
    exit 1
}

このテンプレートでは、文字列結合の曖昧さを防ぐために ${LogPrefix}${DateStr}.log のように変数を波括弧 {} で囲んでいます。変数の直後にアンダースコア(_)や文字が続く場合でも、変数名の境界が明確になりエラーを防げます。


よくある質問(FAQ)

Q: ファイル名に「2026/09/15」のようにスラッシュを入れることはできますか?

A: ファイル名にスラッシュ(/)やコロン(:)を含めることはできません。Windowsのファイルシステム(NTFS)では / \ : * ? " < > | の9文字が予約文字として禁止されているためです。区切り文字を入れたい場合は、yyyy-MM-dd(ハイフン)や yyyy_MM_dd(アンダースコア)を使用してください。

Q: 保存日数ベース(例:30日以上前のログを削除)で書く場合のコードは?

A: Where-Object で LastWriteTime と基準日時を比較する構文を使用します。具体的には以下のコードで30日以上経過したログのみを抽出・削除できます。

$ThresholdDate = (Get-Date).AddDays(-30)
Get-ChildItem -Path "C:\Logs\Backup_*.log" -File |
    Where-Object { $_.LastWriteTime -lt $ThresholdDate } |
    Remove-Item -Force -WhatIf

本番適用時は -WhatIf を外してタスクスケジューラへ組み込んでください。

Q: PowerShell 5.1とPowerShell 7で文字コード(Encoding)の注意点はありますか?

A: Add-Content や Out-File の既定文字コードが異なります。Windows PowerShell 5.1で -Encoding UTF8 を指定すると「BOM付きUTF-8」になりますが、PowerShell 7では「BOMなしUTF-8」が既定になります。古いログ収集ツールやメモ帳での文字化けを防ぐには、環境に合わせ文字コードを明示してください。


まとめ

PowerShellでの「yyyyMMdd」日付取得とログ世代管理のポイントは以下の通りです。

  • 日付の8桁取得は Get-Date -Format "yyyyMMdd" または (Get-Date).ToString("yyyyMMdd") を使用する
  • 書式指定では 大文字の MM(月)と小文字の mm(分)、大文字の HH(24時間制)と小文字の hh(12時間制) を厳密に区別する
  • 変数展開時は ${DateStr}_backup.log のように波括弧 {} で変数名を囲み、後続文字列との連結ミスを防ぐ
  • 古いログの削除は Sort-Object LastWriteTime -Descending | Select-Object -Skip N で最新N世代を確実に保護し、初回は必ず -WhatIf で検証する

定型バッチのログ設計を標準化しておくことで、ディスク枯渇トラブルを未然に防ぎ、障害発生時の調査スピードも大幅に向上します。

関連記事

免責規定

この記事で提供される情報は、一般的なガイダンスを目的としており、すべての環境やシステムでの動作を保証するものではありません。

OSのバージョンやリリースによっては、記載されている事が実行できない、または異なる結果をもたらす可能性があります。 また、会社所有のパソコン、スマホ、タブレットなどでは、ポリシーや権限によって実行できない場合があります。

この記事の情報を使用することによって生じる問題や結果について、筆者およびサイト管理者は責任を負いません。 すべての操作は自己責任で行ってください。

最後までお読みいただきありがとうございました。
またお会いしましょう!

著者のおすすめ教材 & note実践記事

公式教材 豪華4大特典付き

PowerShell実務スクリプト50選

AD・Windows運用・障害対応をコマンド一発で自動化する現役SEの実務スクリプト集。

最新note 毎日定時で帰る現場ハック

ググっても出ない実務テク20選

社内SE現場の地味で細かすぎる面倒作業を一撃で解消する実践テクニック集。