param ( [Parameter(Mandatory=$true)] [string]$SourceFolder ) function Get-MediaCreationDate { param([string]$FilePath) # Try extracting date from filename (YY-MM-DD HH-MM-SS format) $fileName = [System.IO.Path]::GetFileNameWithoutExtension($FilePath) $filenameRegex = '^(\d{2})-(\d{2})-(\d{2})\s(\d{2})-(\d{2})-(\d{2})' if ($fileName -match $filenameRegex) { try { $year = "20" + $matches[1] $month = $matches[2] $day = $matches[3] $hour = $matches[4] $minute = $matches[5] $second = $matches[6] return [datetime]::ParseExact("${year}-${month}-${day} ${hour}:${minute}:${second}", "yyyy-MM-dd HH:mm:ss", $null) } catch {} } # Try Windows Shell metadata try { Add-Type -AssemblyName "System.Windows.Forms" $shell = New-Object -ComObject Shell.Application $folder = $shell.Namespace((Get-Item $FilePath).DirectoryName) $fileItem = $folder.ParseName((Get-Item $FilePath).Name) $dateTaken = $folder.GetDetailsOf($fileItem, 4) if ($dateTaken) { return [datetime]::Parse($dateTaken) } } catch {} # Fallback to file creation time return (Get-Item $FilePath).CreationTime } # Media file extensions to process $mediaExtensions = @('.mp4', '.avi', '.mov', '.mkv', '.wmv', '.jpg', '.jpeg', '.png', '.gif', '.heic') # Get all media files recursively $mediaFiles = Get-ChildItem -Path $SourceFolder -Recurse -File | Where-Object { $mediaExtensions -contains $_.Extension.ToLower() } foreach ($file in $mediaFiles) { try { # Get creation date $creationDate = Get-MediaCreationDate -FilePath $file.FullName # Create target directory structure $targetYear = $creationDate.ToString("yyyy") $targetMonth = $creationDate.ToString("MM") $newFileName = $creationDate.ToString("yyyyMMdd_HHmmss") + $file.Extension $targetFolder = Join-Path -Path $SourceFolder -ChildPath "$targetYear\$targetMonth" # Create target directory if it doesn't exist if (-not (Test-Path -Path $targetFolder)) { New-Item -ItemType Directory -Path $targetFolder | Out-Null } # Full path for new file $newFilePath = Join-Path -Path $targetFolder -ChildPath $newFileName # Avoid overwriting existing files $counter = 1 while (Test-Path -Path $newFilePath) { $newFileName = $creationDate.ToString("yyyyMMdd_HHmmss") + "_$counter" + $file.Extension $newFilePath = Join-Path -Path $targetFolder -ChildPath $newFileName $counter++ } # Move and rename file Move-Item -Path $file.FullName -Destination $newFilePath -ErrorAction Stop Write-Host "Processed: $($file.Name) -> $newFilePath" } catch { Write-Warning "Failed to process $($file.Name): $_" } } Write-Host "Media file renaming complete."