Batch Updating Last Modified Timestamps for Multiple Files

Tech Knowledge
Published on August 24, 2020 Last updated on September 15, 2025
Article Image

はじめに

PowerShell を使用して、フォルダ内のファイルの更新日時を全て同じ日時に変更する手順を紹介します。
サブフォルダ内のファイルも全て処理対象とします。
処理の流れは以下のようになります。

flowchart LR
    A[Get-ChildItem<br>フォルダ内のファイルを列挙] --> B("|"<br>パイプライン演算子)
    B --> A
    B --> C[ForEach-Object<br>各ファイルの処理]
    C --> B

フォルダ内のファイルを列挙

フォルダ内のファイルを列挙するには Get-ChildItem を使用します。
サブフォルダも含めてすべてのファイルを取得するには以下のオプションを指定します。

  • -Recurse: サブフォルダも含めて再帰的に処理
  • -File: ファイルのみを取得(ディレクトリは除外)

例)カレントフォルダ内のファイルを列挙

Get-ChildItem -Recurse -File

例)指定したフォルダ(c:\hoge)内のファイルを列挙

Get-ChildItem -Recurse -File c:\hoge

各ファイルの処理

各ファイルの処理には ForEach-Object を使用します。
ForEach-Object は基本的にパイプライン | 1 を経由して使うことが前提のコマンドです。

| ForEach-Object { 
    # ここに処理を書く
    # 何行書いてもよい
    # $_ はパイプライン内の今処理しているオブジェクト(ファイルやフォルダなど)
    $_.Name  # 今処理しているオブジェクトの名前を表示
}
  • ブロック({} の間)内に処理を記述します。
  • $_ はパイプライン内で「今処理しているオブジェクト」を指します。
  • ブロック内の最後の式の結果が自動的にプロンプトに出力されます(代入した場合は出力されない)。
    たとえば以下の場合、プロセス名の一覧が出力されます。
PS C:\hoge> Get-Process | ForEach-Object { $_.Name }
A5M2
AdobeARM
AggregatorHost
AppActions
armsvc
backgroundTaskHost
backgroundTaskHost
chrome
chrome
・・・
(省略)
・・・
WUDFHost
PS C:\hoge>

更新日時の更新

更新日時を更新するにはオブジェクトの LastWriteTime を設定します。
例)2020年1月1日 0時0分0秒を設定

| ForEach-Object {
    $_.LastWriteTime = [DateTime]'2020-01-01 00:00:00'
}

まとめると

「フォルダ内のファイルを列挙」と「各ファイルの処理」を組み合わせると以下のようになります。

カレントフォルダ内のファイルの更新日時を2020年1月1日 0時0分0秒に更新

Get-ChildItem -Recurse -File | ForEach-Object {
    $_.LastWriteTime = [DateTime]'2020-01-01 00:00:00'
}

指定したフォルダ内のファイルの更新日時を2020年1月1日 0時0分0秒に更新

Get-ChildItem -Recurse -File C:\hoge | ForEach-Object {
    $_.LastWriteTime = [DateTime]'2020-01-01 00:00:00'
}

コマンドレットや引数の省略名を使用すると以下のように書き換えることもできます。

gci -r -File | % { 
    $_.LastWriteTime = '2020-01-01 00:00:00'
}
  • gci = Get-ChildItem
  • -r = -Recurse
  • % = ForEach-Object
  • 日付は文字列でOK(PowerShellDateTime 型に自動変換してくれます)

ワンライナー

以下のように1行で書くこともできます。

gci -r -File | % { $_.LastWriteTime = '2020-01-01 00:00:00' }

現在日時で更新

現在日時で更新するには Get-Date コマンドレットを使用します。

gci -r -File | % { $_.LastWriteTime = Get-Date }

おまけ

テスト用にサブフォルダとファイルを PowerShell で生成

# サブフォルダ数とファイル数の設定
$subfolderCount = 3
$filesPerFolder = 5

# サブフォルダを作成(存在しなければ)
1..$subfolderCount | ForEach-Object {
    $folderName = "SubFolder_$($_)"
    if (-not (Test-Path $folderName)) {
        New-Item -ItemType Directory -Path $folderName | Out-Null
    }
}

# ルートフォルダにもファイルを作る
$targetFolders = @(".") + (Get-ChildItem -Directory | Select-Object -ExpandProperty Name)

foreach ($folder in $targetFolders) {
    1..$filesPerFolder | ForEach-Object {
        $fileName = "file_{0}.txt" -f (Get-Random -Minimum 1000 -Maximum 9999)
        $filePath = Join-Path $folder $fileName
        $content = -join ((65..90) + (97..122) | Get-Random -Count 50 | ForEach-Object {[char]$_})
        Set-Content -Path $filePath -Value $content
    }
}

ランダムな更新日時を設定する

gci -r -File | % {
    $daysOffset = Get-Random -Minimum 0 -Maximum 365
    $randomDate = (Get-Date).AddDays(-$daysOffset).AddHours((Get-Random -Minimum 0 -Maximum 24))
    $_.LastWriteTime = $randomDate
    $_.FullName + " -> " + $randomDate
}

Footnotes

  1. パイプラインとは、コマンドレット同士を |(パイプ記号)でつなぎ、データを順番に渡して処理する仕組み。cmdbash のパイプラインが文字列を渡すのとは異なり、PowerShell のパイプラインは .NET オブジェクトを渡すのが特徴になります。