Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- Dieses Script verarbeitet Google Fotos Takeout-Exporte, ordnet die passenden Metadaten aus den JSON-Dateien den Bild- und Videodateien zu, schreibt diese Metadaten in die Dateien und passt das Dateizeitstempel an. .jfif-Dateien werden automatisch in .jpg umbenannt. Alle Aktivitäten werden in eine "log.txt" geloggt.
- OPTIONAL: In Schritt 3 werden die Originaldateien gelöscht, wenn eine bearbeitete Variante existiert. Ist das nicht gewünscht, diesen Part einfach rauslöschen.
- "exiftool-XXX.zip" hier herunterladen, entpacken, in das Verzeichnis kopieren und die EXE umbenennen in "exiftool.exe": https://exiftool.org/
- Version 1.0.3 - 19.07.2025
- #>
- $exiftoolPath = Join-Path $PSScriptRoot 'exiftool.exe'
- $logPath = Join-Path $PSScriptRoot 'log.txt'
- "`n--- Lauf gestartet: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ---`n" | Out-File $logPath -Encoding UTF8
- # 1. .jfif zu .jpg umbenennen
- Get-ChildItem -Recurse -Filter *.jfif | ForEach-Object {
- try {
- $newPath = $_.FullName -replace '\.jfif$', '.jpg'
- Rename-Item $_.FullName $newPath
- Add-Content $logPath "Umbenannt: $($_.FullName) zu $newPath"
- } catch {
- Add-Content $logPath "FEHLER beim Umbenennen: $($_.FullName) - $_"
- }
- }
- # 2. Umlaute ersetzen
- $extensionstmp = @('*.jpg', '*.jpeg', '*.png', '*.mp4', '*.mov', '*.heic', '*.json')
- # Alle Dateien rekursiv finden
- $files = Get-ChildItem -Path . -Include $extensionstmp -Recurse -File
- foreach ($file in $files) {
- $originalName = $file.BaseName
- $extension = $file.Extension
- $directory = $file.Directory.FullName
- Write-Host "Prüfe: $($file.Name)"
- # Umlaute ersetzen
- $newName = $originalName.Replace("ä", "ae").Replace("ö", "oe").Replace("ü", "ue").Replace("Ä", "Ae").Replace("Ö", "Oe").Replace("Ü", "Ue").Replace("ß", "ss")
- # Prüfen ob Änderung notwendig
- if ($originalName -ne $newName) {
- $newFullName = Join-Path $directory ($newName + $extension)
- if (Test-Path $newFullName) {
- Write-Host "WARNUNG: Zieldatei existiert bereits - übersprungen" -ForegroundColor Yellow
- } else {
- try {
- Write-Host "Benenne um: '$($file.Name)' zu '$($newName + $extension)'"
- Rename-Item -Path $file.FullName -NewName ($newName + $extension)
- } catch {
- Write-Host "FEHLER: $($_.Exception.Message)" -ForegroundColor Red
- }
- }
- } else {
- Write-Host "Keine Änderung erforderlich" -ForegroundColor Gray
- }
- Write-Host ""
- }
- # 3. Dateien erfassen
- $extensions = @('*.jpg', '*.jpeg', '*.png', '*.mp4', '*.mov', '*.heic')
- $files = Get-ChildItem -Recurse -File -Include $extensions
- # 4. Originale löschen, wenn bearbeitete Variante existiert (mit Suffix -bear*)
- $grouped = $files | Group-Object { $_.Name -replace '-bear\w*(?=\.\w+$)', '' }
- foreach ($group in $grouped) {
- $original = $group.Group | Where-Object { $_.Name -notmatch '-bear\w*(?=\.\w+$)' }
- $edited = $group.Group | Where-Object { $_.Name -match '-bear\w*(?=\.\w+$)' }
- if ($original.Count -gt 0 -and $edited.Count -gt 0) {
- foreach ($file in $original) {
- try {
- Remove-Item $file.FullName -Force
- Add-Content $logPath "Original geloescht: $($file.FullName)"
- } catch {
- Add-Content $logPath "FEHLER beim Loeschen: $($file.FullName) - $_"
- }
- }
- }
- }
- # 5. Metadaten schreiben und NTFS-Zeit setzen (mit Endungskorrektur)
- $files = Get-ChildItem -Recurse -File -Include $extensions
- # 5a. Falsche Dateiendungen korrigieren (z.B. PNG mit JPEG-Inhalt)
- foreach ($file in $files) {
- try {
- $magic = Get-Content -Path $file.FullName -Encoding Byte -TotalCount 4
- $isJpeg = ($magic[0] -eq 0xFF -and $magic[1] -eq 0xD8 -and $magic[2] -eq 0xFF)
- $wrongExt = $file.Extension -ieq '.png'
- if ($isJpeg -and $wrongExt) {
- $newPath = [System.IO.Path]::ChangeExtension($file.FullName, '.jpg')
- Rename-Item $file.FullName $newPath -Force
- Add-Content $logPath "Falsche Endung korrigiert: $($file.FullName) zu $newPath"
- }
- } catch {
- Add-Content $logPath "FEHLER bei Endungskorrektur: $($file.FullName) - $_"
- }
- }
- # 5b. Nach Endungskorrekturen erneut Dateiliste holen
- $files = Get-ChildItem -Recurse -File -Include $extensions
- foreach ($file in $files) {
- Write-Host "Bearbeite Datei: $($file.Name)"
- # Basisname bereinigen: ohne -bear*, (Zahl) und evtl. abschließendem _
- $basenameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($file.Name)
- $basenameClean = $basenameWithoutExt -replace '-bear\w*$', '' -replace '\(\d+\)$', '' -replace '_$'
- $base = [regex]::Escape($basenameClean)
- # JSON-Datei suchen mit tolerantem Match (inkl. *.supplemental-metadata(45).json)
- $jsonPath = Get-ChildItem -Path $file.DirectoryName -Filter "*.json" -File | Where-Object {
- $jsonName = $_.Name
- $jsonNameNoExt = [System.IO.Path]::GetFileNameWithoutExtension($jsonName)
- # Klammern und evtl. abschließendes "_" entfernen, aber rest beibehalten
- $jsonNameClean = $jsonNameNoExt -replace '\(\d+\)$', '' -replace '_$'
- # Match wenn Dateiname mit dem bereinigten Basisnamen beginnt und eine "sup*" JSON ist
- $jsonNameClean -eq $basenameClean -or (
- $jsonNameClean -match "^$base" -and $jsonName -match '\.sup(p|pl|plemental)?.*\.json$'
- )
- } | Select-Object -ExpandProperty FullName -First 1
- if (-not $jsonPath) {
- Add-Content $logPath "FEHLER: Keine JSON gefunden: $($file.FullName)"
- continue
- }
- # JSON laden
- try {
- $json = Get-Content $jsonPath -Raw | ConvertFrom-Json
- $description = $json.description
- $timestamp = [double]::Parse($json.photoTakenTime.timestamp)
- $dateTaken = [DateTimeOffset]::FromUnixTimeSeconds($timestamp).ToLocalTime().ToString('yyyy:MM:dd HH:mm:ss')
- } catch {
- Add-Content $logPath "FEHLER beim Parsen: $jsonPath - $_"
- continue
- }
- # ExifTool & NTFS-Zeit setzen
- try {
- & $exiftoolPath `
- -overwrite_original `
- -Description="$description" `
- -EXIF:DateTimeOriginal="$dateTaken" `
- -QuickTime:CreateDate="$dateTaken" `
- -QuickTime:ModifyDate="$dateTaken" `
- -XMP:CreateDate="$dateTaken" `
- -XMP:ModifyDate="$dateTaken" `
- -XMP:DateTimeOriginal="$dateTaken" `
- "$($file.FullName)" | Out-Null
- if ($dateTaken) {
- $escapedPath = $file.FullName.Replace("'", "''")
- $cmd = "powershell -NoLogo -NoProfile -Command ""(Get-Item '$escapedPath').LastWriteTimeUtc = [datetime]::ParseExact('$dateTaken', 'yyyy:MM:dd HH:mm:ss', `$null)"""
- Start-Process -FilePath 'cmd.exe' -ArgumentList "/c $cmd" -NoNewWindow -Wait
- Add-Content $logPath "Metadaten & NTFS-Zeit geschrieben: $($file.FullName)"
- } else {
- Add-Content $logPath "FEHLER: Kein gültiges Datum für NTFS-Zeit bei: $($file.FullName)"
- }
- } catch {
- Add-Content $logPath "FEHLER bei Metadaten/NTFS-Zeit: $($file.FullName) - $_"
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment