Organize Photos with Powershell

Posted On 2016-05-09 by dwirch
Tags: Powershell Scripting Tip Windows
Views: 2766

Like a lot of smartphone users, I like to take pictures. These pictures get automatically synced to my cloud storage, dumping them in a single folder called "Camera Roll". I came up with a quick Powershell script to organize these photos by year and month.

I use a Windows phone, which automatically syncs up with my OneDrive, and thus gets all my devices up to date with pictures that I take with the phone. Users of other devices and services might run into this same problem: All your photos get dumped in the same folder. After awhile, simply viewing the directory listing takes a good amount of time, especially in the web interface.

I needed a quick, automated way to organize the thousands of pictures into subdirectories. The system I came up with was first by year, then by month, with "raw" or "fresh" photos in the "root" directory. So for example, the directory structure including the root directory and the year 2016, with the months January through April, each with 3 pictures would kind of look like this indented list:

  • Camera Roll
    • 2016
      • 01
        • picture2357.jpg
        • picture2358.jpg
        • picture2359.jpg
      • 02
        • picture2360.jpg
        • picture2361.jpg
        • picture2362.jpg
      • 03
        • picture2363.jpg
        • picture2364.jpg
        • picture2365.jpg
      • 04
        • picture2366.jpg
        • picture2367.jpg
        • picture2368.jpg

The problem was that over the years, I haved owned a variety of phones and cameras, all which have dropped picture files into the Camera Roll folder. Not all of the device date-encode their filenames, and instead utilize a simple counter for naming the picture files. Another problem was that each device seemed to use a different format (JPG, GIF, BMP, PNG, etc).

PowerShell can grab all this and process the files with no problem. Here is the script that I came up with in about 10 minutes:

$MyFiles=get-childitem -path c:\OneDrive\MyPictures\* -include *.png,*.jpeg,*.gif,*.jpg,*.psd,*.bmp

ForEach($File in $MyFiles)
$fMonth="{0:00}" -f $file.LastWriteTime.Month

$PathExists=Test-Path $fYear
if($PathExists -eq $false) { mkdir $fYear | out-null }

$PathExists=Test-path $fYear\$fMonth
if($PathExists -eq $false) { mkdir $fYear\$fMonth | out-null }

write-host "Moving $File to $fYear\$fMonth" -ForegroundColor Green
move-item $file $fYear\$fMonth

For those of you who may not be conversant in PowerShell, I'll explain what is going on here.

First, a list of picture files from the "root" directory is stored in $MyFiles. The -include switch is used here because it can reference several different values, whereas -filter can only reference one value. This way, we can get a list of all the picture files into an array in one shot.

Next a loop is started, which steps through all the files in $MyFiles.

The next two lines simply grab the year and month from the file, using the LastWriteTime attribute, storing each value in the appropriate variables (fYear and fMonth).

Now we need to see if the target path actually exists. These four lines can be cleaned up a bit, but this works, and is ok for a quick and dirty script. In these four lines, the path for the year and momth is checked for existence, and if it does not exist, they are created.

Finally, the file is moved to the target path. And since I like to see what is going with my scripts, a notification is written to screen prior to the move.

Like I said, not too complicated, and it helps me to keep my pictures organized. This could also be modified to work with other file types, simply by changing the parameters on the -include switch on the first line. It could used for, say, archiving log files to an alternate location.

I hope you have found this useful!

Improvements? Ideas?

About the Author

has posted a total of 190 articles.

Comments On This Post

By: AnonymousCoward
Date: 2017-08-11

This is exactly what I was looking for!  I'm learning scripting and can't wrap my head around the nuances of making the folders with the month's name instead of the number, but I'll figure that out eventually.

Is there a way to catch the duplicates and place them in a duplicates folder with an autoincrement of +1 to the name so they can be reviewed before deleting?

By: dwirch
Date: 2017-08-11

To catch the duplicate, you'd have look at the list of files currently in the target directory.

If the file exists in the target directory, move on to check the target\duplicates directory for any existing duplicates.

If previous duplicates exist in the target\duplicates directory, find the index of the last duplicate, increment by one, and save with the new filename.

By: AnonymousCoward
Date: 2017-08-11

Ok thank you, I'll approach it from that logic.

Thanks again for your generosity of putting this script out here!

Do you have a thought relating to this post? You can post your comment here. If you have an unrelated question, you can use the Q&A section to ask it.

Or you can drop a note to the administrators if you're not sure where you should post.

Your IP address is:

Before you can post, you need to prove you are human. If you log in, this test goes away.

Code Links