Defca Trick
Defca Trick

Reputation: 315

Powershell Script to Capitalize a letter in the middle of a file name

I was looking for a way adjust the following:

Is there a way to capitalize the S and E ??

I have tried the below but it replaces all E's resulting in:

dir -recurse | where {-Not $_.PsIscontainer -AND $_.name -match "."} | 
foreach {
$New=$_.Basename.Replace(" s"," S").Replace("e","E")+$_.Extension
Rename-Item -path $_.Fullname -newname $New -passthru
}

Thank you so much in advance.

UPDATE:

cd C:\Users\test\Desktop\test
PS C:\Users\test\Desktop\test> dir -recurse | where {-Not $_.PsIscontainer -AND $_.name -match "."} |
>> foreach {
>> $New = $_.Name -replace '(.* )s(\d{2})e(\d{2}\..*)', '$1S$2E$3'
>> Rename-Item -path $_.Fullname -newname $New -passthru
>> }


    Directory: C:\Users\test\Desktop\test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        1/25/2018   2:32 PM              0 Test.Of.Testing.S01e01.this.X264.Mp4
-a----        1/25/2018   2:32 PM              0 Test.Of.Testing.S01E01.this.X264.Mp4
-a----        1/25/2018   2:33 PM              0 Test.Of.Testing.S01e31.this.X264.Mp4
-a----        1/25/2018   2:33 PM              0 Test.Of.Testing.s01E01.this.X264.Mp4

This is what I currently get after swapping in the suggestion from mklement0, it almost looks like nothing changes?

Thanks

Upvotes: 2

Views: 745

Answers (1)

mklement0
mklement0

Reputation: 437608

Your approach didn't work, because the [string] type's .Replace() method invariably replaces all (literal) matches.

Instead, use PowerShell's -replace operator, which is regex-based (using a single file name as an example):

> 'Name s01e01.mp4' -replace '(.*\b)s(\d{2})e(\d{2}\b.*)', '$1S$2E$3'
Name S01E01.mp4

For a concise summary of -replace's behavior, see this answer of mine.

Note:

  • For simplicity, the regex above is designed to match the entire filename, including extension; in the context of the code posted in the question the line therefore needs to be:
    $New = $_.Name -replace '(.*\b)s(\d{2})e(\d{2}\b.*)', '$1S$2E$3'

  • -replace is the same as -ireplace; that is, matching is case-insensitive. Thus, if both the s and the e in question already are uppercased, the replacement is an effective no-op; however, if either or both are lowercased, the replacement ensures that they are uppercased.


To put it all together, using PSv3+ syntax:

Get-ChildItem *.* -Recurse -File |
  Rename-Item -NewName { $_.Name -replace '(.*\b)s(\d{2})e(\d{2}\b.*)', '$1S$2E$3' } 

Note:

  • The PSv3+ -File switch makes Get-ChildItem return files only (similarly, you can ask for directories only with -Directory).

  • *.* as the (implied) -Path argument only matches filenames that contain at least one period (.), which I presume was your intent; by contrast, your attempt to do the same with -match '.' would have matched all filenames, because metacharacter . in a regex represents any single char.

    • On a side note: passing *.* to the -Filter rather than to the -Path argument also matches all filenames, because it is then the Windows API that interprets the wildcard expression, not PowerShell, and for backward-compatibility reasons *.* is treated the same as *.
  • There is no need for a foreach (ForEach-Object) loop, because Rename-Item can accept Get-ChildItem's output directly.

Upvotes: 1

Related Questions