Skip to content

Instantly share code, notes, and snippets.

@TT--
Forked from jongio/PhotoOrganizer.ps1
Last active September 19, 2024 15:37
Show Gist options
  • Save TT--/5c52b1a1c5bde134803aad06bd021cb2 to your computer and use it in GitHub Desktop.
Save TT--/5c52b1a1c5bde134803aad06bd021cb2 to your computer and use it in GitHub Desktop.
A PowerShell script to organize photos by date taken
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