The cmdlet recursively creates a list of files in a source folder and moves or copies unique ones to a destination folder, grouping them by last modified date


function Sort-PhotoVideo
{
    <#
    .SYNOPSIS
    Sorting photos and videos
    .DESCRIPTION
    The cmdlet recursively creates a list of files in a source folder and moves or copies 
	unique ones to a destination folder, grouping them by last modified date
    .PARAMETER SourcePath
    A path to a source folder
    .PARAMETER DestinationPath
    A path to a destination folder
    .PARAMETER Move
    Move files instead of copy
    .INPUTS
    -
    .OUTPUTS
    -    
    .NOTES
    Version 1.1 
    (c) 2018 Alexander Galkov, [email protected]
    .EXAMPLE
    Sort-PhotoVideo -SourcePath "C:\Source" -DestinationPath "C:\Destination" -Move
    .LINK
    www.galkov.pro/powershell_script_for_sorting_photos_and_videos
    #>

    [CmdletBinding()]
    
    Param
    (
        [Parameter(Mandatory=$true)][string]$SourcePath,
        [Parameter(Mandatory=$true)][string]$DestinationPath,
        [Parameter(Mandatory=$false)][switch]$Move
    )

    #showing a warning message about files that are being skipped
    Write-Host "`r`nWARNING: THUMBS.DB FILES ARE BEING SKIPPED THUS THE SIZE OF "
	Write-Host "UNIQUE FILES IN THE SOURCE FOLDER MAY SLIGHTLY DIFFER FROM"
	Write-Host "THE SIZE OF FILES IN THE DESTINATION FOLDER`r`n"

    #creating a list of all files in the source folder
    Write-Host "Creating a list of all files in the source folder..."
    $src_files = Get-ChildItem -Path $SourcePath -File -Recurse -Exclude "thumbs.db" -Force
    Write-Host ("Total number of all the files in the source folder: {0}" -f $src_files.Length)
    $src_files_size = 0
    foreach ($src_file in $src_files)
    {
        $src_files_size += $src_file.Length
    }
    Write-Host ("Total size of all the files in the source folder: {0} B" -f $src_files_size)
    
    #computing hash values of all the files in the source folder
    Write-Host "Computing hash values of all the files in the source folder..."
    $hashes = @{}
    for ($i=0; $i -lt $src_files.Length; $i++)
    {
        $hash = Get-FileHash -Path $src_files[$i].FullName -Algorithm MD5
        if (!$hashes.ContainsKey($hash.Hash))
        {
            $hashes.Add($hash.Hash,$src_files[$i])
        }
        if ($i%[Math]::Ceiling($src_files.Length/10) -eq 0 -or $i -eq $src_files.Length-1)
        {
            write-host ("Processed: {0}%" -f ([Math]::Round(($i+1)/$src_files.Length*100)))
        }
    }
    
    #creating a list of unique files
    Write-Host "Creating a list of unique files in the source folder..."
    $unq_files = 0..($hashes.Values.Count-1)
    $hashes.Values.CopyTo($unq_files,0)
    Write-Host ("Total number of the unique files in the source folder: {0}" -f $unq_files.Length)
    $unq_files_size = 0
    foreach ($unq_file in $unq_files)
    {
        $unq_files_size += $unq_file.Length
    }
    Write-Host ("Total size of the unique files in the source folder: {0} B" -f $unq_files_size)

    #copying/moving the files
    $dst_files = @()
    if ($Move)
    {
        Write-Host "Moving the files..."
    }
    else
    {
        Write-Host "Copying the files..."
    }
    for ($i=0; $i -lt $unq_files.Length; $i++)
    {
        $parent_path = $DestinationPath + "\" + $unq_files[$i].LastWriteTime.Date.ToString("yyyy-MM-dd")
        if (!(Test-Path -Path $parent_path))
        {
            New-Item -ItemType "directory" -Path $parent_path > $null
        }
        $filename = $unq_files[$i].Name
        while (Test-Path -Path ($parent_path + "\" + $filename))
        {
            $dot_pos = $filename.LastIndexOf('.')
            if ($dot_pos -gt -1)
            {
                $filename = $filename.Insert($dot_pos,"!")
            }
            else
            {
                $filename += "!"
            }
        }
        $file_path = $parent_path + "\" + $filename
        if ($Move)
        {
            Move-Item -Path $unq_files[$i].FullName -Destination ($file_path)
        } 
        else
        {
            Copy-Item -Path $unq_files[$i].FullName -Destination ($file_path)
        }
        $dst_files += Get-Item -Path $file_path -Force
        if ($i%[Math]::Ceiling($unq_files.Length/10) -eq 0 -or $i -eq $unq_files.Length-1)
        {
            write-host ("Processed: {0}%" -f ([Math]::Round(($i+1)/$unq_files.Length*100)))
        }
    }

    #creating a list of all files in the destination folder
    Write-Host "Creating a list of all files in the destination folder..."
    Write-Host ("Total number of all the files in the destination folder: {0}" -f $dst_files.Length)
    $dst_files_size = 0
    foreach ($dst_file in $dst_files)
    {
        $dst_files_size += $dst_file.Length
    }
    Write-Host ("Total size of all the files in the destination folder: {0} B" -f $dst_files_size)
}

The cmdlet can also be downloaded here

Leave a Reply