powershellfile-renamepowershell-5.0powershell-5.1rename-item-cmdlet

Rename files sequentially and if file already exists (name conflict) then just increment the iterator to give the file a fresh name


I have this code to mass rename all the .mkv & .mp4 files in the specific directory of my choosing:

$i = 0; Get-ChildItem "$env:Userprofile\Videos\Movie_Best_Clips" -Filter "vlc-record-2024*.mp4" -Recurse | %{Rename-Item $_.FullName -NewName ($_.Directory.Name+'_'+'_{0:D4}.mp4' -f $i++)};
$i = 0; Get-ChildItem "$env:Userprofile\Videos\Movie_Best_Clips" -Filter "vlc-record-2024*.mkv" -Recurse | %{Rename-Item $_.FullName -NewName ($_.Directory.Name+'_'+'_{0:D4}.mkv' -f $i++)};

There are multiple directories inside $env:Userprofile\Videos\Movie_Best_Clips in those folders are the files that match pattern vlc-record-2024*.mp4 or vlc-record-2024*.mkv.

Now I want to, without making any major code altering changes, include a check for whether a file with same name as the name made by iterator exists or not in the given directory, either before or inside Rename-Item line.

If such file already exists then just do continue like behaviour and increment the iterator and subsequently give a fresh name to file, to avoid rename-item errors.

So for example if file with name "MOVIENAME 2024 ENGLISH 1080P.mkv__0002.mp4" already exists(in the same directory as the existing "vlc-record-2024" file* that's to be renamed) then just rename the file in question with "MOVIENAME 2024 ENGLISH 1080P.mkv__0003.mp4" and like that on each and every iteration.

I saw this answer but the answerer has made the code too long, I want to do it in shortest way possible, but can't wrap my head around about how to achieve it, any help is appreciated.


Solution

  • You could probably accomplish this in a single Get-ChildItem call using a hashtable that contains the index for each extension. There is also no need for a ForEach-Object loop if you use a delay-bind scriptblock.

    $i = @{ '.mkv' = 0; '.mp4' = 0 }
    $getChildItemSplat = @{
        Include = 'vlc-record-2024*.mkv', 'vlc-record-2024*.mp4'
        Recurse = $true
        Path    = "$env:Userprofile\Videos\Movie_Best_Clips"
    }
    
    Get-ChildItem @getChildItemSplat | Rename-Item -NewName {
        while ($true) {
            $name = '{0}_{1:D4}{2}' -f $_.Directory.Name, $i[$_.Extension]++, $_.Extension
            if (-not (Test-Path (Join-Path $_.DirectoryName $name))) {
                break
            }
        }
    
        $name
    }