Rename-Item swapping year-month to month-year

I have a large set of pdfs that were erroneously titled:

GW 012000

and I wish to rename them all as:


How do I account for a given set of (source) characters and what would the code look like?

Note the values wouldn’t change (i.e. 2000 would stay 2000 and 01 would stay 01), just the order + the “_” char is added where shown.



you forgot to show us what you’re ve tried so far! :smirk:

'GW 012000' -replace '^(\D+?)\s*(\d{2})(\d{4})','$1_$3_$2'

this is a route but I don’t know about the logic behind matching the structure of the previous filename to a new filename:


#Creation to new dir for copy so I don't screw up my current files
$Temporarydir=  [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory $Temporarydir

#get all file pdf with format REF_ + Number + .pdf and order by number
$ListFile=Get-ChildItem $DirWithFiles -File -Filter "REF_*.pdf" | where BaseName -Match "^REF_\d{1,}$" | select Fullname, Name, @{N="Number";E={[int]($_.BaseName -split '_')[1]}} | sort Number

#copy files into new temporary dir and rename 1 position by N position, 2 by N-1, 3 by N - 2 etc
for ($i = 0; $i -lt ($ListFile.Count / 2 ); $i++)
    Copy-Item $ListFile[$i].FullName "$Temporatydir\$($ListFile[$ListFile.Count-$i - 1].Name)" -Force
    Copy-Item $ListFile[$ListFile.Count-$i - 1].FullName "$Temporatydir\$($ListFile[$i].Name)" -Force

#Copy all files in temporary dir to initial dir with overwriting
Get-ChildItem $Temporatydir | Copy-Item -Destination $DirWithFiles

#delete temporary dir
Remove-Item $Temporatydir -Recurse

hmmm … I didn’t get that, sorry. :man_shrugging:t4:

Your code looks quite confusing to me. And you have one or two typos in your vcariable names: $Temporarydir -vs $Temporatydir.

I’d approach this task like this:

$DirWithFiles = 'C:\sheetmusic'

$Temporarydir = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory $Temporarydir

Get-ChildItem -Path $DirWithFiles -Filter 'REF_*.pdf' -File | 
    Where-Object -Property BaseName -Match -Value '^REF_\d{6}$' | 
        ForEach-Object {
            $NewBaseName = $_.BaseName -replace '^(\D+?)_(\d{2})(\d{4})','$1_$3_$2'
            $NewFilePath = Join-Path -Path $Temporarydir -ChildPath ($NewBaseName + $_.Extension)
            Copy-Item -Path $_.FullName -Destination $NewFilePath

Explorer $Temporarydir

This code will copy files starting with the string REF_ followed by 6 digits to a temporary folder and rename them to the scheme you asked for in your initial question. When the copy job is finished it opens an explorer window showing the temproary folder with the copied and renamed files.

Explanation for the regex logic for the rename operator:

$NewBaseName = $_.BaseName -replace '^(\D+?)_(\d{2})(\d{4})','$1_$3_$2'
  • ^” … matches the start of the search text
  • (\D+?)” … matches 1 or more non digit character (the question mark makes the pattern non greedy)
  • _” … matches an underline
  • “’(\d{2})`” … matches 2 digits
  • (\d{4})” … matches 4 digits

The parts of a pattern inside parenthesis define a match group you can reference later on. This is used in the replacement part of the -replace operator:

  • $1 … references the first match group
  • $2 … references the second match group
  • $3 … references the third match group

… and since we changed the order from 1-2-3 to 1-3-2 the result should be what you asked for. :wink:

1 Like

worked great Olaf, thanks for the work and tutorial

# Alternate method without ForEach-Object
$temporarydir = New-Item -ItemType Directory '\path\to\newfolder' -Force
Get-ChildItem -Path $DirWithFiles -Filter 'REF_*.pdf' | 
Copy-Item -Destination $temporarydir -PassThru | 
Select-Object @{n='Path';exp={$_.FullName}},Name |
Rename-Item -NewName {$_.Name -replace '(^REF_)(\d{2})(\d{4})','$1$3_$2'} -Verbose