Search code examples
powershellrenamefile-renamerename-item-cmdlet

PowerShell optimize Rename-Item -NewName using Split method


In short I'm inserting a hardcoded value 'USA' into the middle of the file name. My code currently works however I feel like it could be optimized, maybe by using -replace operator and RegEx or less returned values (everything before the 4th delimiter '.' + 'USA' + everything after) rather than returning 12 values (0 position + '.' + 1 position + '.' + 2 position + '.' + 3 position + '.' + 'USA' + '.' + 4 position + $_.Extension). Or maybe using the Insert method after the 4th delimiter? I'm iterating through a directory that has several hundreds of subfolders and renaming the '.xlsx' files in the '2023' subfolders. There is usually a folder within '2023' called 'Misc'. I don't want to rename those '.xlsx' files, just the ones in '2023'. I'm sure I can even tighten this up and only look for '.xlsx' files that have 4 '.' in the filename (not inlcuding file entension or new value, 'USA') so I'm not renaming other '.xlsx' files with '.' in the file name.

Current file naming convention: comp_id.process_id.comp_name.state.date.xlsx

Ex: 12345.001.chris_comp.NY.2023_08_22.xlsx

Desired filename naming convention, insert hardcoded value 'USA' after the 4th delimiter '.' so it would look like this: comp_id.process_id.comp_name.USA.date.xlsx

Ex: 12345.001.chris_comp.NY.USA.2023_08_22.xlsx

#renameFile
$numberedFolder = 'C:\Users\Documents\My Documents\PowerShell\Test'
$excludeFolder = 'Misc'
$delimiter = '.'
$excelFile = '.xlsx'
$search = Get-ChildItem -Path $nuberedFolder -Filter '2023' -Recurse
ForEach ($path in $search.fullname) {
Get-ChildItem -Path $path | Where-Object {($_.Extension -match $excelFile)} | 
Rename-Item -NewName {$_.Name.Split($delimiter)[0] + '.' + $_.Name.Split($delimiter)[1] + '.' + $_.Name.Split($delimiter)[2] + '.' + $_.Name.Split($delimiter)[3] + '.' + 'USA' + '.' + $_.Name.Split($delimiter)[4] + $_.Extension} -WhatIf
}

Solution

  • Indeed, the regex-based -replace operator offers a concise solution:

    ... |
     Rename-Item -NewName { $_.Name -replace '(?:[^.]+\.){4}', '$&USA.' } -WhatIf
    

    For an explanation of the regex and the substitution expression, along with the option to experiment with them, see this regex101.com page.


    Furthermore, you can streamline your overall command as follows:

    Get-ChildItem -Directory -Recurse -LiteralPath $numberedFolder -Filter '2023' |
      Get-ChildItem -File -Filter '*.*.*.*.*.xlsx' |
      Rename-Item -NewName { $_.Name -replace '(?:[^.]+\.){4}', '$&USA.' } -WhatIf