Search code examples
powershellfile-renameget-childitem

Rename-Item renaming issue


I am wrote some code and the first time it worked fine. However, I've now replaced the files with new dummy files and I'm now getting the following:

MyTestFile.zip is changed to MyTestFile_zip.zip_zip.zip MyTestFile.prd is changed to MyTestFile_prd.prd_prd.prd

Here's the code:

Get-ChildItem -Filter "*.prd" -Recurse | Rename-Item -NewName {$_.name -replace '.prd','_prd.prd'}
Get-ChildItem -Filter "*.zip" -Recurse | Rename-Item -NewName {$_.name -replace '.zip','_zip.zip'} 

Got any ideas how I can avoid this problem?

Thanks


Solution

  • The -replace operator

    • takes a regular expression as its first operand and
    • performs substring matching by default.

    Therefore, you must modify the regex that is the first operand for the replacement to work as intended:

    $_.Name -replace '\.prd$','_prd.prd' 
    
    • . is escaped as \. to make sure that -replace treats it as a literal; without the \, . would match any character.

    • $ ensures that the expression is anchored to the end of the input, i.e., only matches at the end.

    A more generic reformulation that covers both .prd and .zip:

    $_.Name -replace '\.(prd|zip)$','_$1.$1' 
    

    See below for an explanation.

    If we put this all together, we can get away with a single pipeline:

    Get-ChildItem -File *.prd, *.zip -Recurse | 
      Rename-Item -NewName { $_.Name -replace '\.(prd|zip)$','_$1.$1' }
    

    Use of regular expressions allows you to process more than one extension at a time, and also allow you to reference parts of what the regular expression matched (captured) through capture groups (parenthesized subexpressions) that you can reference as $1 (1st capture group, ...) in the replacement string

    > @( 'example.zip', 'example.prd' ) -replace '\.(prd|zip)$','_$1.$1'
    example_zip.zip
    example_prd.prd
    

    Note how $1 in the replacement string refers to whatever capture group (prd|zip) captured, which is zip for the first input, and prd for the second.