RadFox
RadFox

Reputation: 419

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

Upvotes: 2

Views: 488

Answers (2)

whatever
whatever

Reputation: 891

Editor's note: While this answer doesn't work for the specific question at hand, because it inserts an extraneous ., it does show the use of [System.IO.Path]::ChangeExtension() as a robust way to change a file's extension in general.

Alternatively use the .net method to change the file extension:

Get-ChildItem -Filter "*.prd" -Recurse | Rename-Item -NewName {[System.IO.Path]::ChangeExtension($_.name,"_prd.prd")}

Upvotes: 1

mklement0
mklement0

Reputation: 439912

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.

Upvotes: 3

Related Questions