Last active
July 8, 2022 22:59
-
-
Save jtmoon79/eea39c3f9b3d37a169286da8f7788512 to your computer and use it in GitHub Desktop.
set filesystem datetime of jpg and mp4 files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!powershell | |
<# | |
.SYNOPSIS | |
Use exiftool to set file system datetimes values to those found within embedded media | |
tags of .mp4 and .jpg files. | |
.DESCRIPTION | |
Use exiftool (https://exiftool.org/) to set file system datetime attributes | |
FileModifyDate, FileAccessDate, FileCreateDate. | |
The various datetime values can be seen with command: | |
exiftool.exe -time:all -groupHeadings -duplicates file.mp4 | |
.PARAMETER Path | |
File system path to search for .jpg files and .mp4 files. | |
.PARAMETER Help | |
Print the help message and return. | |
.LINK | |
https://gist.github.com/jtmoon79/eea39c3f9b3d37a169286da8f7788512 | |
.NOTES | |
Author: James Thomas Moon | |
Date: 2022 | |
#> | |
[Cmdletbinding()] | |
Param ( | |
[string] $Path, | |
[switch] $help | |
) | |
New-Variable -Name SCRIPT_NAME -Value "set-datetime-of-pics-vids.ps1" -Option ReadOnly -Force | |
if ($help) { | |
Get-Help "${PSScriptRoot}\${SCRIPT_NAME}" -Full | |
Return | |
} | |
# save current values, restore at script end | |
$erroractionpreference_ = $ErrorActionPreference | |
$ErrorActionPreference = "Stop" | |
#Set-PSDebug -Trace 1 | |
function PrintDates | |
{ | |
Param( | |
[Parameter(Mandatory=$true)][String]$file | |
) | |
Write-Verbose "$exiftool -time:all -groupHeadings -short -duplicates '$file'" | |
& "$exiftool" -time:all -groupHeadings -short -duplicates $file | |
} | |
# functions Process* | |
# set the file system file attributes (`File:FileAccessDate` is typically not writable) | |
# | |
# XXX: `File:FileAccessDate` sometimes ends up matching the last changed datetime value, | |
# i.e. a change to `File:FileModifyDate` has a side-affect of setting `File:FileAccessDate` | |
# to the same value. | |
# | |
# BUG: `File:FileCreateDate` often fails to change, will `ForceCreateDate` help? | |
# most likely failure is due to the file being on a Unix Samba share, and | |
# the Samba share settings disallowing this change due to some combination | |
# of factors | |
function ForceCreateDate { | |
Param( | |
[Parameter(Mandatory=$true)][String]$file | |
) | |
$date_lastwritetime = (Get-Item $file).LastWriteTime | |
(Get-Item $file).CreationTime = $date_lastwritetime | |
} | |
function ProcessJPG | |
{ | |
Param( | |
[Parameter(Mandatory=$true)][String]$file | |
) | |
Write-Verbose "$exiftool '$file'" | |
# first use `EXIF:DateTimeOriginal` which is sometimes available and sometimes correct | |
# then use `EXIF:CreateDate` which is sometimes avilable and often correct | |
# hopefully the most appropriate date is used | |
# | |
# XXX: the camera picture file embedded tagging varies tremendously; this works for my | |
# set of .jpg files | |
& "$exiftool" -verbose -verbose -extractEmbedded ` | |
'-EXIF:DateTimeOriginal>File:FileCreateDate' ` | |
'-EXIF:CreateDate>File:FileCreateDate' ` | |
'-EXIF:DateTimeOriginal>File:FileModifyDate' ` | |
'-EXIF:CreateDate>File:FileModifyDate' ` | |
$file | |
} | |
function ProcessMP4 | |
{ | |
Param( | |
[Parameter(Mandatory=$true)][String]$file | |
) | |
Write-Verbose "$exiftool '$file'" | |
# set the file system file attributes (`File:FileAccessDate` is typically not writable) | |
& "$exiftool" -verbose -verbose -extractEmbedded ` | |
'-Quicktime:CreateDate>File:FileCreateDate' ` | |
'-Quicktime:CreateDate>File:FileModifyDate' ` | |
$file | |
} | |
function ProcessAVI | |
{ | |
Param( | |
[Parameter(Mandatory=$true)][String]$file | |
) | |
Write-Verbose "$exiftool '$file'" | |
# set the file system file attributes (`File:FileAccessDate` is typically not writable) | |
& "$exiftool" -verbose -verbose -extractEmbedded ` | |
'-RIFF:DateTimeOriginal>File:FileCreateDate' ` | |
'-RIFF:DateTimeOriginal>File:FileModifyDate' ` | |
$file | |
} | |
try { | |
# XXX: fallback path is hardcoded to my location | |
$exiftool = "$HOME\Apps\exiftool-12.42\exiftool.exe" | |
if ($null -ne (Get-Command "exiftool.exe" -ErrorAction SilentlyContinue)) { | |
$exiftool = ( | |
Get-Command "exiftool.exe" -CommandType Application -TotalCount 1 | ForEach-Object { | |
"$_" | |
} | |
) | |
} | |
# verify exiftool can run | |
& "$exiftool" -ver | |
$compare = [System.StringComparison]::CurrentCultureIgnoreCase | |
# user passed single .jpg file | |
if ((Test-Path -Path $Path -PathType Leaf) -AND ( | |
$Path.EndsWith(".jpg", $compare) -OR $Path.EndsWith(".jpeg", $compare) | |
) | |
) { | |
# see datetime attributes before | |
PrintDates $Path | |
ProcessJPG $Path | |
# see datetime attributes after | |
PrintDates $Path | |
# user passed single .mp4 file | |
} elseif ((Test-Path -Path $Path -PathType Leaf) -AND $Path.EndsWith(".mp4", $compare)) { | |
# see datetime attributes before | |
PrintDates $Path | |
ProcessMP4 $Path | |
# see datetime attributes after | |
PrintDates $Path | |
# user passed single .avi file | |
} elseif ((Test-Path -Path $Path -PathType Leaf) -AND $Path.EndsWith(".avi", $compare)) { | |
# see datetime attributes before | |
PrintDates $Path | |
ProcessAVI $Path | |
# see datetime attributes after | |
PrintDates $Path | |
# user passed directory | |
} elseif (Test-Path -Path $Path -PathType Container) { | |
Get-ChildItem $Path -Recurse -File -Filter "*.jpg" ` | |
| Sort-Object -Property FullName ` | |
| ForEach-Object { ProcessJPG $_ } | |
Get-ChildItem $Path -Recurse -File -Filter "*.jpeg" ` | |
| Sort-Object -Property FullName ` | |
| ForEach-Object { ProcessJPG $_ } | |
Get-ChildItem $Path -Recurse -File -Filter "*.mp4" ` | |
| Sort-Object -Property FullName ` | |
| ForEach-Object { ProcessMP4 $_ } | |
Get-ChildItem $Path -Recurse -File -Filter "*.avi" ` | |
| Sort-Object -Property FullName ` | |
| ForEach-Object { ProcessAVI $_ } | |
# user passed unhandled file | |
} else { | |
Write-Error "Unhandled file $Path" | |
} | |
} catch { | |
# set `$ErrorActionPreference` *before* calling `Write-Error` | |
$ErrorActionPreference = "Continue" | |
Write-Error $_.ScriptStackTrace | |
Write-Error -Message $_.Exception.Message | |
} finally { | |
# restore to original shell value | |
$ErrorActionPreference = $erroractionpreference_ | |
# presumably was already 0 | |
#Set-PSDebug -Trace 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment