Organizing my pictures, evolving the script to my taste

I ran the PowerShell script I discussed in my previous blogpost and decided I would change it a bit.

First, I want to be able to sort by month within the year so I have two options:
- change the folder name to following pattern MM-DD-YY
- Add a level to the folder structure so it becomes:
     - Year
        - Month
           - Day

Second, from my 24 GB of pictures on that machine, only 17GB got copied over. The rest didn’t because of exceptions or because I had the same picture in multiple folders. In order not to loose any pictures I changed the script so:
- it writes the error message to a text file
- it copies the .jpg on which the exception was generated to an exceptions folder

So now it gets interesting. Kim has got me developing Powershell code. I never thought I would ever do that since it seems more something an IT Professional would do but there are some advantages to writing this sort of job as a script:

  1. It is quick and a bit dirty.
  2. Powershell has non-terminating errors. This reminds me of ‘On Error Resume Next’ and how I kept my VB6 code clean at the time :-)
  3. I could easily schedule this as a recurring job.

Here’s how I deal with this:

Step 1. I switch to PowerShell 2 because that’s on my Windows 7 machine but more importantly because you then have the Windows PowerShell Integrated Scripting Environment. That’s a tool for running and debugging scripts so exactly what I need.
If you are on Vista you can get it here: https://www.microsoft.com/downloads/details.aspx?FamilyID=c913aeab-d7b4-4bb1-a958-ee6d7fe307bc&displaylang=en

Step 2. I learn about error handling and debugging in PowerShell. This seems like a good place. It’s an old blog series but I’m sure still very relevant: https://blogs.msdn.com/monad/archive/2005/11.aspx
Also install the SDK from the download link in Step 1.

Step 3. Changing the script.

Changing the folder structure is easy. you change it:
from: $DateTaken = $strDay + "-" + $strMonth + "-" + $strYear
$TargetPath = "c:\temp\organized pictures\" + $strYear + "\" + $DateTaken

to: $TargetPath = "c:\temp\organized pictures\" + $strYear + "\" + $strMonth + "\" + $strDay

Fixing the exceptions and adding the exception list is something else. But with the new Try..Catch…Finally structure in PowerShell 2, it is not that difficult at all. I highlighted the interesting sections:

#==============================================================================================
#
# AUTHOR:  Kim Oppalfens
# DATE  : 12/2/2007, updated by Hans Verbeeck on 10 Jan 2009
#
# COMMENT: Helps you organize your digital photos into a directory structure, based on the Exif data
# found inside the picture. Based on the date picture taken property the pictures will be organized into
# c:\organizedfotos\YYYY\MM\
# ==============================================================================================

[reflection.assembly]::loadfile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll")

$targetFolder = "c:\temp\organized pictures\"
$exceptionFolder = "c:\temp\organized pictures\Exceptions"

#make sure you create this folder yourself as the script won't do that automatically

$Files = Get-ChildItem -recurse -filter *.jpg
foreach ($file in $Files)
{

try
{
  $foo=New-Object -TypeName system.drawing.bitmap -ArgumentList $file.fullname
  write-host $file.fullname -foregroundcolor Blue

#each character represents an ascii code number 0-10 is date
#10th character is space separator between date and time
#48 = 0 49 = 1 50 = 2 51 = 3 52 = 4 53 = 5 54 = 6 55 = 7 56 = 8 57 = 9 58 = :
#date is in YYYY/MM/DD format
  $date = $foo.GetPropertyItem(36867).value[0..9]
  $arYear = [Char]$date[0],[Char]$date[1],[Char]$date[2],[Char]$date[3]
  $arMonth = [Char]$date[5],[Char]$date[6]
  $arDay = [Char]$date[8],[Char]$date[9]
  $strYear = [String]::Join("",$arYear)
  $strMonth = [String]::Join("",$arMonth)
  $strDay = [String]::Join("",$arDay)
  $DateTaken = $strDay + "-" + $strMonth + "-" + $strYear
  $TargetPath = $targetFolder + $strYear + "\" + $strMonth + "\" + $strDay

If (Test-Path $TargetPath)
      {
        xcopy /Y/Q $file.FullName $TargetPath
      }
      Else
       {
        New-Item $TargetPath -Type Directory
        xcopy /Y/Q $file.FullName $TargetPath
       }
}
catch
   {
    $logtext = "`n" + $file.fullname + " FAILED"
Add-Content c:\temp\imagecopyexceptions.txt $logtext
$logtext = $Error[$error.count-1]
Add-Content c:\temp\imagecopyexceptions.txt $logtext


xcopy /Y/Q $file.FullName $exceptionFolder

}
}