-
-
Save TT--/5c52b1a1c5bde134803aad06bd021cb2 to your computer and use it in GitHub Desktop.
A PowerShell script to organize photos by date taken
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
Param( | |
[Parameter(mandatory)] | |
[string]$source, | |
[Parameter(mandatory)] | |
[string]$dest, | |
[string]$format = "yyyy-MM-dd", | |
[bool]$dryrun = $False | |
) | |
$shell = New-Object -ComObject Shell.Application | |
function Get-File-Date { | |
[CmdletBinding()] | |
Param ( | |
$object | |
) | |
$dir = $shell.NameSpace( $object.Directory.FullName ) | |
$file = $dir.ParseName( $object.Name ) | |
# First see if we have Date Taken, which is at index 12 | |
$date = Get-Date-Property-Value $dir $file 12 | |
#Write-Host "debug -- Date Taken: (from Get-Date-Property-Value index 12): $date" | |
if ($null -eq $date) { | |
Write-Host "Could not get Date Taken for $object" | |
return | |
## If we don't have Date Taken, then find the oldest date from all date properties | |
#0..287 | ForEach-Object { | |
# $name = $dir.GetDetailsof($dir.items, $_) | |
# if ( $name -match '(date)|(created)') { | |
# | |
# # Only get value if date field because the GetDetailsOf call is expensive | |
# $tmp = Get-Date-Property-Value $dir $file $_ | |
# if ( ($null -ne $tmp) -and (($null -eq $date) -or ($tmp -lt $date))) { | |
# $date = $tmp | |
# } | |
# } | |
#} | |
} | |
return $date | |
} | |
function Get-Date-Property-Value { | |
[CmdletBinding()] | |
Param ( | |
$dir, | |
$file, | |
$index | |
) | |
#$value = ($dir.GetDetailsof($file, $index) -replace "`u{200e}") -replace "`u{200f}" | |
$value = ($dir.GetDetailsof($file, $index) -replace "`\u200e|") -replace "`\u200f|" | |
if ($value -and $value -ne '') { | |
#Write-Host "debug -- GetDetailsof after character replacement: $value" | |
#return [DateTime]::ParseExact($value, "g", $null) | |
return [DateTime]::ParseExact($value, 'yyyy-MM-dd h:mm tt', $null) | |
} | |
return $null | |
} | |
Get-ChildItem -Attributes !Directory $source -Recurse | | |
Foreach-Object { | |
#Write-Host "Processing $_" | |
Write-Host "Processing $($_.FullName)" | |
if (!(('.jpg','.jpeg','.gif','.png').Contains($_.Extension.ToLower()))) { | |
Write-Host "Skipping because extension is: $($_.Extension)" | |
return | |
} | |
$date = Get-File-Date $_ | |
#Write-Host "debug -- Get-File-Date result: $date" | |
if ($date) { | |
$destinationFolder = Get-Date -Date $date -Format $format | |
$destinationPath = Join-Path -Path $dest -ChildPath $destinationFolder | |
# See if the destination file exists and rename until we get a unique name | |
$newFullName = Join-Path -Path $destinationPath -ChildPath $_.Name | |
if ($_.FullName -eq $newFullName) { | |
Write-Host "Skipping: Source file and destination files are at the same location. $_" | |
return | |
} | |
$newNameIndex = 1 | |
$newName = $_.Name | |
if (Test-Path -Path $newFullName) { | |
Write-Host "Skipping file as destination already exists" | |
return | |
} | |
while (Test-Path -Path $newFullName) { | |
$newName = ($_.BaseName + "_$newNameIndex" + $_.Extension) | |
$newFullName = Join-Path -Path $destinationPath -ChildPath $newName | |
$newNameIndex += 1 | |
} | |
# If we have a new name, then we need to rename in current location before moving it. | |
if ($newNameIndex -gt 1) { | |
Rename-Item -Path $_.FullName -NewName $newName | |
} | |
Write-Host "Moving $_ to $newFullName `r`n" | |
if (!$dryRun) { | |
# Create the destination directory if it doesn't exist | |
if (!(Test-Path $destinationPath)) { | |
New-Item -ItemType Directory -Force -Path $destinationPath | |
} | |
robocopy $_.DirectoryName $destinationPath $newName /mov | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment