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
- 01
- 2016
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)
{
$fYear=$File.LastWriteTime.Year
$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?