powershellrename-item-cmdlet

PowerShell command to insert 1 character in the middle of a filename


Have a directory of images named like IMG_xxxx.JPG, where x is an integer. I need to insert a "1" after the underscore, so each name becomes IMG_1xxxx.JPG.

I tried this in PowerShell:

Dir | Rename-Item -NewName { $_.name -replace "_","_1" }

and it worked on a number of the files in my directory, however, it went crazy on some others, and tried to add a seemingly infinite loop of 1s to some of the filenames. Error message was:

Rename-Item : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters. At line:1 char:7 + Dir | Rename-Item -NewName { $.name -replace "","_1" } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : WriteError: (C:\Users\michel...11111111109.JPG:String) [Rename-Item], PathTooLongExcepti on + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

Happy for an alternate approach here. Understanding what I actually did wrong is a secondary goal to getting this rename done! Thanks.


Solution

  • I guess the problem is that the pipeline runs while Get-ChildItem is still enumerating the files. You should probably first enumerate all files, and then rename them, so that renamed files don't get picked up twice:

    (dir) | rename-Item -new { $_.name -replace '_','_1' }
    

    The parentheses ensure that dir is first evaluated completely and its result then passed through the rest of the pipeline. it's conceptually the same as

    $files = dir
    $files | rename-item ...
    

    Another option would be to check whether you need to rename the file at all:

    dir | where { $_.Name -match '_\d{4}\D' } | rename-item -NewName { ... }