====== PowerShell et la photo ======
===== Organiser ces photos avec la lecture de l'exif =====
L'EXIF, c'est un format de fichier utilisé pour les images prises par un appareil photographique numérique, la première version de l'Exif date de 1995.\\ **C'est une mine d'or pour organiser ces photos.**\\ Je suis tombé sur le travail de **Jon Gallant**, [[https://blog.jongallant.com/2021/03/organize-photos-powershell/|sur son blog ]], depuis je n'utilise que ce script.\\ Attention pour les utilisateurs de la suite Adobe, on est loin des capacités d'un [[https://helpx.adobe.com/camera-raw/using/navigate-open-save-images-camera.html|Adobe Camera Raw]].
Param(
[string]$source,
[string]$dest,
[string]$format = "yyyy/MM_yyyy/dd_MM_yyyy"
)
$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
if ($null -eq $date) {
# 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}"
if ($value -and $value -ne '') {
return [DateTime]::ParseExact($value, "g", $null)
}
return $null
}
Get-ChildItem -Attributes !Directory $source -Recurse |
Foreach-Object {
Write-Host "Processing $_"
$date = Get-File-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
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"
# 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
}
}
==== Lire des informations EXIF dans un fichier image ====
Function Get-Image
{
begin{
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") |Out-Null
}
process{
$fi=[System.IO.FileInfo]$_
if( $fi.Exists){
$img = [System.Drawing.Image]::FromFile($_)
$img.Clone()
$img.Dispose()
}else{
Write-Host "File not found: $_" -fore yellow
}
}
end{}
}
Get-ChildItem -Path "F:\Wallpaper" -Filter *.jpg | ForEach-Object {
$image = $_ | Get-Image
New-Object PSObject -Property @{
File = $_.name
Fullname = $_.Fullname
Height = $image.Height
Width = $image.Width
};
}
===== Effacer les dossiers vides =====
# Set to true to test the script
$whatIf = $false
# Remove hidden files, like thumbs.db
$removeHiddenFiles = $false
# Get hidden files or not. Depending on removeHiddenFiles setting
$getHiddelFiles = !$removeHiddenFiles
# Remove empty directories locally
Function Delete-EmptyFolder($path)
{
# Go through each subfolder,
Foreach ($subFolder in Get-ChildItem -Force -Literal $path -Directory)
{
# Call the function recursively
Delete-EmptyFolder -path $subFolder.FullName
}
# Get all child items
$subItems = Get-ChildItem -Force:$getHiddelFiles -LiteralPath $path
# If there are no items, then we can delete the folder
# Exluce folder: If (($subItems -eq $null) -and (-Not($path.contains("DfsrPrivate"))))
If ($subItems -eq $null)
{
Write-Host "Removing empty folder '${path}'"
Remove-Item -Force -Recurse:$removeHiddenFiles -LiteralPath $Path -WhatIf:$whatIf
}
}
# Run the script
Delete-EmptyFolder -path "E:\_Backup"
===== Déplacer les fichiers par date vers un autre dossier =====
Je n'utilise plus cette version de script, je préfère utiliser le script avec l'utilisation des informations EXIF
$Destination = 'F:\Photos\'
$Source = 'F:\Photos\2019'
Get-ChildItem -Path $Source -File -Filter *.jpg -Recurse| ForEach-Object {
$Year = $_.lastwritetime.year.ToString("0000")
$Month = $_.lastwritetime.month.ToString("00")
$Day = $_.lastwritetime.day.ToString("00")
$D = Join-Path $Destination -ChildPath "$Year\$Month-$Year\$Day-$Month-$Year"
if ((Test-Path $D) -eq $false){New-Item -Path $D -ItemType Directory -Force | Out-Null}
Move-Item -Path $_.FullName -Destination (Join-Path -Path $D -ChildPath $_.name ) -Force
}