PowerShell: Rename Photo and Video Files by Adding Creation Dates

Have you ever downloaded a punch of images, MOV, and MP4 from iCloud to find that Windows displays their Creation Dates as the same value of your download time. It’s difficult to group photos in such views. Although Explorer does have the feature to display ‘Date taken’ attribute for image files by enabling certain ‘columns,’ such equivalent labeling for videos are hard to locate. You’re in luck, I’ve written a PoSH function to address this very issue by adding date stamps onto file names for easy scanning.

Window Explorer View of downloaded iCloud Photos
Windows option to show ‘Date taken’ column for JPEG files
Lubuntu Linux PCMANFM-QT View of downloaded iCloud Photos
# renamePhotosByDateTaken.ps1
# Version: 0.0.1
# Author: KimConnect.com

$mediaDirectory='\\tsclient\Desktop\iCloud Photos'

function renameMediaFilesByAddingDates{
    function getMediaDateTaken($filePath,$propertyIndex){        
            $propertyIndex=switch -regex ($filePath){
                '(JPG|PNG|GIF|BMP|TIFF|JPEG)+$' {12}
                '(MOV|MP4|AVI|MPG|MPEG|WMV|QT|FLV|SWF)+$' {208} # Assuming Windows 10
            $shell = New-Object -COMObject Shell.Application
            $shellFolder = $shell.Namespace($(split-path $filePath))
            $shellFile = $shellFolder.ParseName($(split-path $filePath -leaf))
            # How to view all attributes: 0..287|%{'{0}: {1}' -f $_,$shellFolder.GetDetailsOf($shellFile,$_)}
            $dateTakenUnicode=$shellFolder.GetDetailsOf($shellFile, $propertyIndex)
            [datetime]$dateTaken=$dateTakenUnicode -replace '[^\d^\:^\w^\/^\s]'
            return $dateTaken
            write-host $_
            return $false

    # This function reveals the index number of properties by names
    function getFileAttributes ([string[]]$filePath){
        $shell = New-Object -COMObject Shell.Application
        $shellFolder = $shell.Namespace($(split-path $filePath))
        $shellFile = $shellFolder.ParseName($(split-path $filePath -leaf))
        $attributes = @()
        0..287 | ForEach-Object {
            $propertyName = $shellFolder.GetDetailsOf($shellFolder, $_)
            $propertyValue = $shellFolder.GetDetailsOf($shellFile, $_)       
            #write-host "$propertyName`: $propertyValue"
            if($propertyName -ne '' -and $null -ne $propertyName){
                # Avoid this error:
                #Item has already been added. Key in dictionary: ''  Key being added: ''
                #At line:5 char:13
                #+             $attributes+=@{$propertyName=$propertyValue}
                #+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                #    + CategoryInfo          : OperationStopped: (:) [], ArgumentException
                #    + FullyQualifiedErrorId : System.ArgumentException
        return $attributes
    if (test-path "$mediaDirectory\Thumbs.db:encryptable" -ea SilentlyContinue){
        # remove-item -literalPath "$mediaDirectory\Thumbs.db:encryptable"
        write-warning "Retry this program after this file is deleted: $targetFile"
        return $false
    $regexMediaFile=($regexPhotoFile -replace '[)+$]') +'|'+ ($regexVideoFile -replace '\(')
    $allMediaFiles=Get-ChildItem $mediaDirectory -Recurse|?{!$_.PSisContainer -and $_.FullName -match $regexMediaFile}

    <# Note on an file name issue in media directories as Windows autogens a file named 'Thumbs.db:encryptable' that is an invalid file name
    Get-ChildItem : The given path's format is not supported.
    At line:1 char:11
    + $allFiles=Get-ChildItem $mediaDirectory -ea SilentlyContinue
    +           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [Get-ChildItem], NotSupportedException
        + FullyQualifiedErrorId : System.NotSupportedException,Microsoft.PowerShell.Commands.GetChildItemCommand
    Remove any file name that has illegal characters, specifically 'Thumbs.db:encryptable'
    if ($allMediaFiles){
        $fileAttributes=getFileAttributes $allFiles[0].FullName # generate this variable once to speed up runtime
        write-host "Retrieving the creation date of each media file..."
        foreach ($item in $allMediaFiles){
            $propertyIndex=switch -regex ($filePath){
                $regexPhotoFile {($fileAttributes|?{$_.Name -eq 'Date taken'}).index }
                $regexVideoFile {($fileAttributes|?{$_.Name -eq 'Media created'}).index} # Assuming Windows 10
                if($filePath -match $regexMediaFile){
                    return getMediaDateTaken $filePath $propertyIndex
                    #return $item.CreationTime
                    return $false
                write-host "$fileName`: $dateCreated"
                write-host "$fileName`: SKIPPED!"

        #$maxFileNameLength=255 # Assuming legacy Windows 7 compatibility
        foreach ($file in $mediaFiles.GetEnumerator()){
                $newFilePath=if($maxCharFeasible -ge 16){
                    }elseif($maxCharFeasible -ge 11){
                    }elseif($maxCharFeasible -ge 8){
                    }elseif($maxCharFeasible -ge 5){
                # Confirm the first 3 files
                if($count++ -lt 3){
                    write-host "`r`nRenaming $filePath to`r`n$newFilePath ?`r`n--- Ctrl+C to cancel ---"
                    write-host "$newFilePath"
                rename-item $filePath $newFilePath -force
                Write-Host $_

        write-host "Done."
        return $true
        write-host "Unable to retrieve list of media files from directory $mediaDirectory"
        return $false

renameMediaFilesByAddingDates $mediaDirectory
Sample Output:
Renaming \\tsclient\Desktop\iCloud Photos\IMG_0379.JPEG to
\\tsclient\Desktop\iCloud Photos\IMG_0379-11-23-2019-2010.JPEG?
--- Ctrl+C to cancel ---
Press Enter to continue...:
Renaming \\tsclient\Desktop\iCloud Photos\IMG_0570.JPEG to
\\tsclient\Desktop\iCloud Photos\IMG_0570-01-01-2020-1535.JPEG?
--- Ctrl+C to cancel ---
Press Enter to continue...:
Renaming \\tsclient\Desktop\iCloud Photos\IMG_0392.JPEG to
\\tsclient\Desktop\iCloud Photos\IMG_0392-11-23-2019-2012.JPEG?
--- Ctrl+C to cancel ---
Press Enter to continue...:
--- Truncated for brevity --- 

One thought on “PowerShell: Rename Photo and Video Files by Adding Creation Dates”

  1. I get the following error:
    Cannot convert value “1472022 14:54” to type “System.DateTime”. Error: “De tekenreeks is niet als geldige DateTime herkend.”

    (String is not recognized as a valid DateTime)
    Using Win10.

    Do you have any idea?

Leave a Reply

Your email address will not be published. Required fields are marked *