IO/Rename/Rename-GitFileWithRegex.ps1

<#
Use this to bulk rename files
 
Will combine the RegexPrefix, Find and RegexSuffix into a regex case-sensitive compare on the whole filename (including extension)
 
Will
 
use with care.
 - Try on a small folder and don't recurse first to make sure it does what you expect.
 - Use -whatif and/or -nogit to see if it does what you expect
 
Initially this was designed to rename the systemService part of our stashes so it is in camelCase.
However GIT (in our windows configuration) doesn't cope with renames where only case is different
 
Designed specifically to cope with renaming files where only case is different.
This is tricky with GIT as it wont detect a difference if only case has changed,
so we rename through another change by adding !!! to the filename also
 
.EXAMPLE
 
--------------------------
1. Rename in a 2 stage process from Salesforce to salesforce and keep GIT consistent
 
$renameParams = @{
    Folder = '.\somePath\'
    Find = '([_.]|\b|^)Salesforce([_.])'
    Replace = '$1salesforce$2'
    CaseOnlyChange = $true
}
.\script\Rename-GitFile.ps1 @renameParams
 
--------------------------
2. Rename stash folders, files and contents of files
 
## Set the following variables and run the full example (can run individually if you like)
$folder = '.\somePath\'
$replacePairs = @(
    [PSCustomObject]@{Original = 'Mds'; Replace = 'mds'}
    [PSCustomObject]@{Original = 'Salesforce'; Replace = 'salesforce'}
    [PSCustomObject]@{Original = 'DwFtp'; Replace = 'dwFtp'}
)
 
foreach ($replacePair in $replacePairs)
{
    ## 2.1 rename folders
    $renameParams = @{
        Folder = "$folder\\Source"
        Find = "$($replacePair.Original)(\..*)"
        Replace = "$($replacePair.replace)`$1"
        Directory = $true
        CaseOnlyChange = $true
    }
    .\script\Rename-GitFile.ps1 @renameParams
 
    ## 2.2 rename files (everywhere)
    $renameParams = @{
        Folder = $folder
        Find = "(.+(?:\.|_))$($replacePair.Original)((?:\.|_).+)"
        Replace = "`$1$($replacePair.Replace)`$2"
        Recurse = $true
        CaseOnlyChange = $true
    }
    .\script\Rename-GitFile.ps1 @renameParams
 
    ## 2.3 rename contents of files
    foreach ($file in (Get-ChildItem $folder -include '*.sql','*.json' -recurse))
    {
        $pattern = "(\.|_|\[)$($replacePair.Original)(\.|_)"
        $contents = Get-Content $file -raw
        if ($contents -cMatch $pattern) {
            $contents -cReplace $pattern,"`$1$($replacePair.Replace)`$2" | Out-File $file -NoNewline
        }
    }
    git add $Folder
    git commit -m 'completed rename contents'
}
celestra # fix database project
 
--------------------------------
 
.NOTES
 
Remember you will need to run celestra in many cases to ensure that the auto files are built with correct casing
 
You will also be able to use vscodes find in files with similar regex to easily rename objects
#>

function Rename-GitFileWithRegex {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        <#Category#>'PSShouldProcess',<#CheckId#>'',
        Justification = 'called functions handle it'
    )]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        # path to folder to rename
        [string]$Folder,
        # whether to recurse from folder through subfolders
        [switch]$Recurse,
        # case-sensitive Find string.
        [string]$Find,
        # replace string use $1/$2 etc to replace with brackets
        [string]$Replace,
        # use this switch if renaming directories
        [switch]$Directory
    )
    Set-StrictMode -version 2
    $ErrorActionPreference = 'Stop'

    try {
        $2stageRename = $true # if you don't want this just use Rename-Files

        # this will allow renaming a set of files case sensitively and it will work with git correctly
        # rename with a safe additional character so that it isn't only case that has changed
        $stage1Match = $Find
        $stage1Replace = '!!!$0'
        $stage2Match = "!!!$Find"
        $stage2Replace = $Replace

        $RenameParams = @{
            Folder     = $Folder
            Directory  = $Directory.IsPresent
            Recurse    = $Recurse.IsPresent
            Find       = $stage1Match
            Replace    = ($2stageRename ? $stage1Replace : $stage2Replace)
            GitMessage = 'rename stage 1 of 2'
        }
        Rename-FileWithRegex @RenameParams

        if ($2stageRename) {
            $RenameParams.Find = $stage2Match
            $RenameParams.Replace = $stage2Replace
            $RenameParams.GitMessage = 'rename stage 2 of 2'
            Rename-FileWithRegex @RenameParams
        }
    } catch {
        throw
    }
}