MRが楽しい

MRやVRについて学習したことを書き残す

PowerShellでフォルダ内のファイル名のフォーマットを一括変更する

本日はPowerShellの小ネタ枠です。
PowerShellでフォルダ内のファイル名のフォーマットを一括変更する方法です。

フォルダ内のファイルを一括取得する

Get-ChildItem関数を利用すると指定のフォルダ内のファイルやフォルダを取得できます。
パラメータを指定することで取得対象をファイルまたはフォルダに絞ることも可能です。
learn.microsoft.com

// 指定パス配下にあるディレクトリの一覧を取得する
Get-ChildItem -Path C:\Test -Directory

ファイル名のフォーマットを変更する

match演算子正規表現を利用して指定のフォーマットから合致するパターンを取得することができます。
learn.microsoft.com

match演算子を使って以下のようにフォーマットパターンに一致した文字列を抽出して新たな文字列を生成できます。

// 変更前のフォーマット文字列 (任意の文字)-(任意の数字).(拡張子)
$oldName = "abc-123.txt"
if ($oldName -match "^(.+)-([0-9]+)\.(.+)$") {
    # $Matches変数に一致した文字列が収納される
    $namePart = $matches[1]   # 名前部分
    $numberPart = $matches[2] # 数字部分
    $extension = $matches[3]  # 拡張子部分

    # 変更後のフォーマット文字列 (任意の数字)_(任意の文字).(拡張子)
    $NewName = "${numberPart}_${namePart}\.${extension}"
}

サンプルスクリプト

指定フォルダのパスを引数で受け取り、指定フォルダ内のファイルまたはフォルダ名のフォーマットを変更する以下のサンプルスクリプトを作成しました。

# 1つ目の引数を要求する
# 引数を指定していなかった場合は対話形式で入力を要求する
Param(
	[parameter(mandatory)][String]$argment01
)

# 指定されたディレクトリが存在するか確認
if (-not (Test-Path $argment01 -PathType Container)) {
    Write-Host "Error:The specified directory does not exist."
    exit
}

# 受け取った引数を変更対象のディレクトリとして指定する
$targetDirectory = $argment01

# 実行メッセージを表示する
Write-Host ("Target Directory is " + $targetDirectory)

# ディレクトリ内のフォルダを取得
$items = Get-ChildItem -Path $targetDirectory

# マッチングするフォルダの確認フラグ
$matchFound = $false
foreach ($item in $items) {
    # フォルダ名を取得
    $oldName = $item.Name
    Write-Host ("Target FileFile is " + $oldName)

    # 正規表現で "任意の名前(任意の数字)""任意の数字_任意の名前" に変換
    if ($oldName -match "^(.+)\(([0-9]+)\)(\..+)?$") {
        $namePart = $matches[1]   # 名前部分
        $numberPart = $matches[2] # 数字部分
        $extension = $matches[3]  # 拡張子(ファイルのみ)

        # 名前または数字部分が空の場合はスキップ
        if (-not $namePart -or -not $numberPart) {
            Write-Output "Skipped: $($item.Name) is not in the correct format."
            continue
        }

        # マッチングフラグをON
        $matchFound = $true

        # 新しい名前を作成(拡張子があればファイル、なければフォルダ)
        if ($extension) {
            $newName = "${numberPart}_${namePart}${extension}"
            $oldPath = $item.FullName
            $newPath = Join-Path $item.DirectoryName $newName
        } else {
            $newName = "${numberPart}_${namePart}"
            $oldPath = $item.FullName
            $newPath = Join-Path $item.Parent.FullName $newName
        }

        if (-not (Test-Path $newPath)) {
            Rename-Item -Path $oldPath -NewName $newName
            Write-Output "Renamed: $oldName -> $newName"
        } else {
            Write-Output "Skipped: $newName already exists"
        }
    }
    else
    {
        Write-Output "Skipped: $($item.Name) is not in the correct format."
    }
}

# フォーマットが一致するフォルダまたはファイルがなかった場合はメッセージを表示する
if (-not $matchFound) {
    Write-Output "No corresponding folder or file was found."
}

以下の通り同様の名前フォーマットを持つファイルまたはフォルダを持つパスを指定して実行してみます。

結果全てのファイルとフォルダの名前のフォーマットを一括変更できました。