ただし、撮影日時が未来の日付だったり1970年代だったりと不正な値の場合はファイル名を変更せずスキップしてください。 また、リネームしようとしたファイル名のファイルが既に存在した場合は、ファイル名の後に通し番号をつけてください。 ファイル名を変更した際は、Rename 旧ファイル名(ディレクトリパス含まず) -> 新ファイル名 というプロンプトを表示するようにしてください。
以下のPowerShellスクリプトは、指定された条件を満たす形で実装されています。このスクリプトを .ps1
ファイルとして保存して実行してください。
# 必要なモジュールのインポート
Add-Type -AssemblyName System.Drawing
# カレントディレクトリのjpgファイルを取得
Get-ChildItem -Path . -Filter *.jpg | ForEach-Object {
$file = $_
$fullPath = $file.FullName
$fileName = $file.Name
try {
# EXIF情報の取得
$image = [System.Drawing.Image]::FromFile($fullPath)
$prop = $image.PropertyItems | Where-Object { $_.Id -eq 0x9003 } # 撮影日時プロパティ
$image.Dispose()
if ($prop -ne $null) {
# 撮影日時の抽出
$dateTaken = [System.Text.Encoding]::ASCII.GetString($prop.Value).TrimEnd([char]0)
$parsedDate = [datetime]::ParseExact($dateTaken, "yyyy:MM:dd HH:mm:ss", $null)
# 日付の妥当性チェック (未来の日時または1970年以前を無効とする)
if ($parsedDate -gt (Get-Date) -or $parsedDate.Year -lt 1970) {
Write-Output "Skip $fileName: Invalid date ($dateTaken)"
return
}
# 新しいファイル名の生成
$newFileName = $parsedDate.ToString("yyyyMMddHHmmss") + ".jpg"
$newFilePath = Join-Path -Path (Get-Location) -ChildPath $newFileName
$counter = 1
# 重複するファイル名がある場合は通し番号を付加
while (Test-Path $newFilePath) {
$newFileName = $parsedDate.ToString("yyyyMMddHHmmss") + "_$counter.jpg"
$newFilePath = Join-Path -Path (Get-Location) -ChildPath $newFileName
$counter++
}
# ファイルのリネーム
Rename-Item -Path $fullPath -NewName $newFileName
Write-Output "Rename $fileName -> $newFileName"
} else {
Write-Output "Skip $fileName: No EXIF date information"
}
} catch {
Write-Output "Error processing $fileName: $_"
}
}
カレントディレクトリ内のJPEGファイルを取得
Get-ChildItem
を使用して、カレントディレクトリ内の .jpg
ファイルをリストアップします。
EXIF情報の撮影日時プロパティを取得
撮影日時プロパティ(ID: 0x9003)を取得します。
日付の妥当性を確認
撮影日時が未来または1970年以前の場合はスキップします。
新しいファイル名を生成
撮影日時を元に YYYYMMDDHHMMSS.jpg
形式の新しいファイル名を生成し、重複があれば通し番号を付加します。
リネームの実行とログの出力
ファイルをリネームし、変更内容を Rename 旧ファイル名 -> 新ファイル名
形式で出力します。
以下の修正版では、変数を適切に ${}
形式で囲みました。これにより、スクリプトが期待どおりに動作するはずです。
# 必要なモジュールのインポート
Add-Type -AssemblyName System.Drawing
# カレントディレクトリのjpgファイルを取得
Get-ChildItem -Path . -Filter *.jpg | ForEach-Object {
$file = $_
$fullPath = $file.FullName
$fileName = $file.Name
try {
# EXIF情報の取得
$image = [System.Drawing.Image]::FromFile($fullPath)
$prop = $image.PropertyItems | Where-Object { $_.Id -eq 0x9003 } # 撮影日時プロパティ
$image.Dispose()
if ($prop -ne $null) {
# 撮影日時の抽出
$dateTaken = [System.Text.Encoding]::ASCII.GetString($prop.Value).TrimEnd([char]0)
$parsedDate = [datetime]::ParseExact($dateTaken, "yyyy:MM:dd HH:mm:ss", $null)
# 日付の妥当性チェック (未来の日時または1970年以前を無効とする)
if ($parsedDate -gt (Get-Date) -or $parsedDate.Year -lt 1970) {
Write-Output "Skip ${fileName}: Invalid date (${dateTaken})"
return
}
# 新しいファイル名の生成
$newFileName = $parsedDate.ToString("yyyyMMddHHmmss") + ".jpg"
$newFilePath = Join-Path -Path (Get-Location) -ChildPath $newFileName
$counter = 1
# 重複するファイル名がある場合は通し番号を付加
while (Test-Path $newFilePath) {
$newFileName = $parsedDate.ToString("yyyyMMddHHmmss") + "_$counter.jpg"
$newFilePath = Join-Path -Path (Get-Location) -ChildPath $newFileName
$counter++
}
# ファイルのリネーム
Rename-Item -Path $fullPath -NewName $newFileName
Write-Output "Rename ${fileName} -> ${newFileName}"
} else {
Write-Output "Skip ${fileName}: No EXIF date information"
}
} catch {
Write-Output "Error processing ${fileName}: $_"
}
}
$fileName
を ${fileName}
に置き換えました。このスクリプトを実行して動作確認してください。
このエラーが発生した場合200ミリ秒ごとに5回まで処理をリトライしてください。5回とも失敗した場合はエラーとみなして処理を停止してください。