I like to organize my home pictures and videos by the year and month. Sometimes, I will organize them base on the subject . I am tired to do it manually and decide to write a PowerShell script to do.
Now, here you go: orag-photo.ps1
The script does very simple tasks:
- Scan the files and distribute the file base on the last write date property of the file.
- If no target directory is provided, it is default as same as source directory.
- When source directory and target directory are the same, it is running as MOVE mode.
- When source directory and target directory are not the same, it is running as COPY mode.
- If the script found the target directory has the same file name, it will use MD5 check sum to compare. unless the –force flag is provided, it wont overwrite the target file whether they are the same or not.
- By default, the script is running as dry run mode, it wont really perform the actual work but only show you what it will do. use –doit flag to let the script perform the actual work.
- The script will skip the directory where it has YYYYXXX, YYYY is the digital number, XXX can be any string. For example, 2013NY_FAMILY_TRIP
Here is the screen shot when it runs in dry run mode.
Here is the screen shot when it runs in doit flag.
Here is the end result of the sorting .
-reverse flag can move all the files back to its root but it wont delete the timestamp folder.
More example can be found with –example flag
Here is the source code of the script. Enjoy
<#
.SYNOPSIS
Helps you organise your digital photos/videos into subdirectory, based on the last write date.
.DESCRIPTION
Helps you organise your digital photos/videos into subdirectory, based on the last write date.
Last Write date usually is the date taken when the file is created.
Bsae on the date, the file will be organized into C:\targe_directory\YYYY\YYYYMM
The script will auto skip special folder name like YYYYXX, example, 2013NYTRIP.
As I may organize my photo in this naming and I dont want it to be autosort.
.NOTES
Author: Po@sqlpanda
File: Org-Photos.ps1
Requires: PowerShell V2
.LINK
WWW.SQLPANDA.COM
.EXAMPLE
orag-photo -src C:\Users\PO\Pictures\
Dry run the file processing. Give you the overview what the script will do.
.EXAMPLE
orag-photo -src C:\Users\PO\Pictures\ -verbose
Dry run the file processing with verbose output. Give you the overview what the script will do.
.EXAMPLE
orag-photo -src C:\Users\PO\Pictures\ -target C:\temp -doit
Actuall move the files and organize the in the folder. Skip if the file has the same name or MD5 check show difference.
.EXAMPLE
orag-photo -src C:\Users\PO\Pictures\ -target C:\temp -doit
Actuall copy the files and organize the in the folder. Skip if the file has the same name or MD5 check show difference.
.EXAMPLE
orag-photo -src C:\Users\PO\Pictures\ -target C:\temp -doit -force
Actuall copy the files and organize the in the folder. Overwrite all files even with the same name or MD5 check show difference.
.PARAMETER src
Soruce directory
.PARAMETER target
target directory. Deftaul to be the same as source
.PARAMETER doit
Without doit flag, it will only create the report and tell you what it will do
.PARAMETER force
Overwrite the file with the same name and MD5 checksum show the difference
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$src,
[switch]$doit,
[string]$target,
[switch]$force,
[switch]$reverse
)
function getMD5{
Param (
$c_file
)
$md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($c_file)))
$hash
}
if ( $target ){
}
else {
$target=$src
}
#todo Better error checking for compare $src and $target
Write-Host "Target: $target"
Write-Host "Source: $src"
if ( (Test-path "$src") -ne $True ) {
Write-Host "Source Dir does not exist."
break
}
If ( $target -eq $src ) {
Write-Host "++MOVE_MODE: source directory is same as target directory"
$cmd_mode = 'Move-Item'
$cmd_string = 'Move'
}
else {
Write-Host "++COPY_MODE: source directory is different than target directory"
$cmd_mode = 'Copy-Item'
$cmd_string = 'Copy'
}
$Files = Get-ChildItem -recurse "$src"
$num_entry_in_src = ($Files ).count
Write-Verbose "Num of Entry in the Source: $num_entry_in_src"
If ( $num_entry_in_src -eq 0){
Write-Host "No File found in Source directory."
}
$exclude_foders = @()
$want_files =@()
foreach ($file in $Files)
{
#TODO add progress bar
#TODO move flag to write-verbose
$full_name = $file.fullname
if ( $file.PSIsContainer -eq $true ){
write-verbose "$full_name is directory"
}
else {
# check special name directory
$file_dir_name = $file.Directory.Name
$file_full_dir_name = $file.DirectoryName
if ( $file_dir_name -match '^\d\d\d\d[a-zA-Z_]'){
Write-verbose "DIR: $file_full_dir_name"
Write-verbose "File directory match exclude naming convention"
$exclude_foders += ,$file_full_dir_name
continue
}
$last_writeTime = $file.LastWriteTime
If ($last_writeTime.day -lt 10){
$strDay = '0' + [string] $last_writeTime.day
}
else {
$strDay = [string] $last_writeTime.day
}
$strYear = [string] $last_writeTime.year
If ( $last_writeTime.month -lt 10){
$strMonth = '0' + [string] $last_writeTime.month
}
else {
$strMonth = [string] $last_writeTime.month
}
$DateTaken = $strYear + $strMonth + $strDay
$MonthTaken = $strYear + $strMonth
$file | Add-Member –MemberType NoteProperty –Name myDataTaken –Value $DateTaken
$file | Add-Member –MemberType NoteProperty –Name myMonth –Value $MonthTaken
$file | Add-Member –MemberType NoteProperty –Name myYear –Value $strYear
$myDataTaken = $file.myDataTaken
Write-verbose "$full_name -> DayTaken: $myDataTaken,MonthTaken:$MonthTaken,YearTaken:$strYear "
$want_files += ,$file
}
}
if ( $doit -eq $true ){
$flag= '++DOIT:'
}
else {
$flag = '++DRYRUN'
}
# Create the folder
$folder_create_arrary = @()
$file_new_arrary = @()
$file_md5_diff_overwrite_arrary = @()
$file_md5_diff_non_overwrite_arrary = @()
$file_md5_same_overwrite_array= @()
$file_md5_same_non_overwrite_arrary = @()
foreach ($file in $want_files) {
$month_dir = $file.myMonth
$year_dir = $file.myYear
If ( $reverse -eq $true) {
$full_new_dir=$target
}
else {
$full_new_dir = "$target\$year_dir\$month_dir"
}
$full_path = $file.fullname
$TimeStamp = $file.myDataTaken
$short_name = $file.name
$new_file_path = "$full_new_dir\$short_name"
if ( (Test-path $full_new_dir) -eq $true ){
Write-host "$full_new_dir already exist."
}
else {
# create dir
$folder_create_arrary += ,$full_new_dir
if ( $doit -eq $true ){
write-host "++DOIT: $full_new_dir does not exist . creating ..."
mkdir "$full_new_dir" | out-null
}
else {
Write-host "$flag $full_new_dir does not exist . creating ..."
}
}
If ( (test-path $new_file_path) -eq $true ){
# Same file name exist
$target_md5 = getMD5("$new_file_path")
$src_md5 = getMD5("$full_path")
if ( "$src_md5" -eq "$target_md5"){
# MD5 same
If ( $force -eq $true){
# OverWrite FIle
$file_md5_same_overwrite_array += ,$file
Write-host "$flag $short_name($TimeStamp) is the same between source and target. Force flag in place."
if ( $doit -eq $true ){
& $cmd_mode "$full_path" "$full_new_dir" -force
}
}
else {
Write-host "I am here"
$file_md5_same_non_overwrite_array += ,$file
Write-host "$flag $short_name is the same between source and target. No action taken."
}
}
else {
# MD5 Diff
Write-Verbose "SRC: $src_md5"
Write-Verbose "TAR: $target_md5"
If ( $force -eq $true){
$file_md5_diff_overwrite_arrary += ,$file
Write-host "$flag $short_name($TimeStamp) is different between soruce and target."
if ( $doit -eq $true ){
& $cmd_mode "$full_path" "$full_new_dir"
}
}
else {
$file_md5_diff_non_overwrite_arrary += ,$file
Write-host "$flag $short_name($TimeStamp) is different between soruce and target."
}
}
}
else {
# new files
$file_new_arrary += ,$file
if ( $doit -eq $true ){
Write-host "$flag $cmd_string $full_path($TimeStamp) to $full_new_dir"
& $cmd_mode "$full_path" "$full_new_dir"
}
else {
Write-host "$flag $cmd_string $full_path($TimeStamp) to $full_new_dir"
}
}
}
# Summary Report
Write-Host ''
Write-Host '################################################'
Write-Host "########### Summery Report ##########"
Write-Host '################################################'
if ($reverse -eq $true){
Write-Host "*** Reverse flag is enable. Pull files back to the $target as flat."
}
Write-Host "* Target: $target"
Write-Host "* Source: $src"
Write-Host "* Command Mode: $cmd_mode"
Write-Host "* Flag: $flag"
Write-Host "* Numer of the Folders created :" ($folder_create_arrary | Sort-Object -Unique).count
Write-Host "* Numer of the New Files :" ($file_new_arrary ).count
Write-Host "* Numer of the same files found(overwrite):" ($file_md5_same_overwrite_array ).count
Write-Host "* Numer of the same files found( Keep ):" ($file_md5_same_non_overwrite_array ).count
#$file_md5_same_non_overwrite_array
Write-Host "* Numer of the diff files found(overwrite):" ($file_md5_diff_overwrite_array ).count
Write-Host "* Numer of the diff files found( Keep ):" ($file_md5_diff_non_overwrite_array ).count
Write-Host ''
Write-Host "* Numer of the Skip Dir for name exclusion:" ($exclude_foders | Sort-Object -Unique).count
$exclude_foders | Sort-Object -Unique
0 comments:
Post a Comment