日付毎にファイルをサブフォルダに移動

スマートフォンからパソコンに動画や写真を移すと、一つのフォルダに数千ものファイルが溜まってしまい、目的のファイルを探すのが大変になることはありませんか?

この問題を解決するため、AIのGeminiに依頼して、大量のファイルを撮影日ごとに自動でフォルダ分けするPowerShellスクリプトを作成してもらいました。

このスクリプトを使えば、乱雑になりがちなフォルダ内がすっきりと整理され、過去のデータも簡単に見つけられるようになります。

# -----------------------------------------------------------------------------
# 説明: 画像ファイルを撮影日時のフォルダに整理するスクリプト
# -----------------------------------------------------------------------------

# 1. 画像が保存されているフォルダのパスを指定してください
$targetFolder = "C:\Users\YourUser\Pictures\Camera Roll" # 実際のフォルダパスに書き換えてください

# 2. 処理対象とするファイルの拡張子 (必要に応じて追加・削除してください)
$imageExtensions = @(".jpg", ".jpeg", ".png", ".heic", ".cr2", ".nef", ".arw", ".mov", ".mp4")

# -------------------------- ここから下は変更不要 --------------------------

# フォルダの存在チェック
if (-not (Test-Path -Path $targetFolder)) {
    Write-Error "エラー: 指定されたフォルダが見つかりません。パスを確認してください: $targetFolder"
    return
}

Write-Host "📁 処理を開始します。対象フォルダ: $targetFolder" -ForegroundColor Green

try {
    # Shellオブジェクトを使用してファイルの詳細情報にアクセスします
    $shell = New-Object -ComObject Shell.Application
    $folder = $shell.NameSpace($targetFolder)

    # 「撮影日時」の項目が何番目にあるかを探します (環境により異なるため)
    $dateTakenIndex = -1
    for ($i = 0; $i -lt 300; $i++) {
        $header = $folder.GetDetailsOf($null, $i)
        if ($header -eq "撮影日時" -or $header -eq "Date taken") {
            $dateTakenIndex = $i
            break
        }
    }

    # フォルダ内の対象ファイルを一つずつ処理
    Get-ChildItem -Path $targetFolder -File | Where-Object { $imageExtensions -contains $_.Extension.ToLower() } | ForEach-Object {
        $file = $_
        $dateTaken = $null

        # 撮影日時を取得
        if ($dateTakenIndex -ne -1) {
            $folderItem = $folder.ParseName($file.Name)
            if ($folderItem) {
                # GetDetailsOfは文字列を返す
                $dateValue = $folder.GetDetailsOf($folderItem, $dateTakenIndex)
                # 文字列からDateTimeオブジェクトへの変換を試みる
                if (-not [string]::IsNullOrWhiteSpace($dateValue)) {
                    # 日付文字列に含まれることがある特殊文字を除去
                    $cleanedDateString = $dateValue -replace '[\u200E\u200F\u202A-\u202E]',''
                    try {
                        $dateTaken = [datetime]::Parse($cleanedDateString)
                    } catch {}
                }
            }
        }

        # 撮影日時が取得できなかった場合は、ファイルの最終更新日時を使用
        if ($null -eq $dateTaken) {
            $dateTaken = $file.LastWriteTime
            Write-Warning "[$($file.Name)] の撮影日時が取得できませんでした。代わりに更新日時 (${dateTaken}) を使用します。"
        }

        # 移動先のフォルダ名を「yyyyMMdd」形式で作成
        $subFolderName = $dateTaken.ToString("yyyyMMdd")
        $destinationFolder = Join-Path -Path $targetFolder -ChildPath $subFolderName

        # 移動先フォルダがなければ作成
        if (-not (Test-Path -Path $destinationFolder)) {
            Write-Host "新しいフォルダを作成します: $subFolderName" -ForegroundColor Cyan
            New-Item -Path $destinationFolder -ItemType Directory -Force | Out-Null
        }

        # ファイルを移動
        $destinationPath = Join-Path -Path $destinationFolder -ChildPath $file.Name
        Move-Item -Path $file.FullName -Destination $destinationPath
        Write-Host "'$($file.Name)' -> '$subFolderName'"
    }
}
catch {
    Write-Error "予期せぬエラーが発生しました: $_"
}
finally {
    # COMオブジェクトを解放
    if ($shell) {
        [System.Runtime.InteropServices.Marshal]::ReleaseComObject($shell) | Out-Null
        Remove-Variable shell -ErrorAction SilentlyContinue
    }
}

Write-Host "✅ すべての処理が完了しました。" -ForegroundColor Green

実行完了すると8桁の表現(例 20250716)のフォルダ別にファイルが移動されます。利用にあたっては、自己責任でお願いします。 #gemini #powershell

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です