Powershell/Windows Batch/VB Script: replace string in folders and files

Luis Diaz
Luis Diaz used Ask the Experts™
on
Hello experts,

I am looking for a batch, powershell or vbscript to cover the following requirement:

-Loop a reported folder with drill down
-Check the various files and folder
-Replace SourceString by TargetString
-SourceString and TargetString should be reported as parameter

-Example:
BaseDir= C:\Test
SourceString= “_”
TargetString “-“

-Various files and folders which contains source string “_” should be replaced by target  “-“.

If you have questions, please contact me.
Thank you.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Bill PrewIT / Software Engineering Consultant
Top Expert 2016

Commented:
Are the replacements being made in the file name?  Of folders and files, or just files?  Or the extension?


»bp
Most Valuable Expert 2018
Distinguished Expert 2018

Commented:
Save this as Rename-ItemRecurse.ps1 or Whatever.ps1 (not in test mode, see below).
You can pass the start path, the source string, and the target string as parameters; if an argument is not passed, the defaults will be taken  from the command line.
In addition, you can use the following arguments:
-Verbose
-WhatIf (test mode, will not rename anything)
-Confirm (will list and prompt before renaming anything)
Examples:
.\Rename-ItemRecurse.ps1 -Path C:\toto -WhatIf
.\Rename-ItemRecurse.ps1 -Confirm

Open in new window

[CmdletBinding(SupportsShouldProcess=$true)]
Param(
	[Parameter(Position=0)]
	[string]$Path = 'C:\Test',
	[Parameter(Position=1)]
	[string]$SourceString = '_',
	[Parameter(Position=2)]
	[string]$TargetString = '-'
)
$verbose = $PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters['Verbose'].ToBool()
$pattern = [regex]::Escape($SourceString)

Get-ChildItem -Path $Path -File -Recurse |
	Where-Object {$_.Name -match $pattern} |
	Rename-Item -NewName {$_.Name -replace $pattern, $TargetString} -Verbose:$verbose

Get-ChildItem -Path $Path -Directory -Recurse |
	Where-Object {$_.Name -match $pattern} |
	Sort-Object -Property @{e={$_.FullName.Split('\').Count}} -Descending |
	Rename-Item -NewName {$_.Name -replace $pattern, $TargetString} -Verbose:$verbose

Open in new window

Bill PrewIT / Software Engineering Consultant
Top Expert 2016

Commented:
If you are just talking about doing the replacements in file names (not folder names) then this should work.

@echo off
setlocal EnableDelayedExpansion

set BaseDir=B:\EE\EE29144987\test
set SourceString=_
set TargetString=-

for /f "tokens=*" %%A in ('dir /b /s /a-d "%BaseDir%\*%SourceString%*.*"') do (
    set FileName=%%~nA
    set FileName=!FileName:%SourceString%=%TargetString%!
    ren "%%~A" "!FileName!%%~xA"
)

Open in new window


»bp
PMI ACP® Project Management

Prepare for the PMI Agile Certified Practitioner (PMI-ACP)® exam, which formally recognizes your knowledge of agile principles and your skill with agile techniques.

Luis DiazIT consultant

Author

Commented:
Hello,
Is it possible to have flag to calibrate the procedure. 1 for file names 2 for folder names.
Batches and powershell approaches?
Thank you very much for your help.
The procedure concerns file names and not extensions.
Most Valuable Expert 2018
Distinguished Expert 2018
Commented:
On closer inspection, seems like I misinterpreted your "parameters".
This now has the settings hardcoded (test/confirm/verbose modes still available as described above).
Processing of files and/or folders can be enabled or disabled individually (currently does both).
It is now in test mode (variable $testMode), and when processing files, it will ignore extensions when matching.
$baseDir = 'C:\Test'
$sourceString = '_'
$targetString = '-'
$processFiles = $true
$processFolders = $true
$testMode = $true
$confirm = $false
$verbose = $true

$pattern = [regex]::Escape($SourceString)
If ($processFiles) {
	Get-ChildItem -Path $baseDir -File -Recurse |
		Where-Object {$_.BaseName -match $pattern} |
		Rename-Item -NewName {"$($_.BaseName -replace $pattern, $TargetString)$($_.Extension)"} -Verbose:$verbose -WhatIf:$testMode -Confirm:$confirm
} Else {
	Write-Warning 'Processing of files is disabled!'
}
If ($processFolders) {
	Get-ChildItem -Path $baseDir -Directory -Recurse |
		Where-Object {$_.Name -match $pattern} |
		Sort-Object -Property @{e={$_.FullName.Split('\').Count}} -Descending |
		Rename-Item -NewName {$_.Name -replace $pattern, $TargetString} -Verbose:$verbose -WhatIf:$testMode -Confirm:$confirm
} Else {
	Write-Warning 'Processing of folders is disabled!'
}

Open in new window

Shaun VermaakTechnical Specialist
Awarded 2017
Distinguished Expert 2018

Commented:
I would just use fnr.exe - Find And Replace Tool for this
358a59e5-8789-4779-b131-0cf89b5a0286.pnghttps://archive.codeplex.com/?p=findandreplace
IT / Software Engineering Consultant
Top Expert 2016
Commented:
This should handle folders as well as files now, driven by a variable.

@echo off
setlocal EnableDelayedExpansion

set BaseDir=B:\EE\EE29144987\test
set SourceString=_
set TargetString=-
set ProcessFiles=Y
set ProcessFolders=Y

if /i "%ProcessFiles%" EQU "Y" (
    for /f "tokens=*" %%A in ('dir /b /s /a-d "%BaseDir%\*%SourceString%*.*"') do (
        set FileName=%%~nA
        set FileName=!FileName:%SourceString%=%TargetString%!
        ren "%%~A" "!FileName!%%~xA"
    )
)

if /i "%ProcessFolders%" EQU "Y" (
    for /f "tokens=*" %%A in ('dir /b /s /ad "%BaseDir%\*%SourceString%*.*" ^| sort /r') do (
        set FileName=%%~nA
        set FileName=!FileName:%SourceString%=%TargetString%!
        ren "%%~A" "!FileName!%%~xA"
    )
)

Open in new window


»bp
Luis DiazIT consultant

Author

Commented:
Thank you very much! Unable to test right now I will keep you informed!
Luis DiazIT consultant

Author

Commented:
Question: espace " " Can be reported as SourceString?
Example: replace " " by  "-".
SourceString= " "
TargetString= "-"
Most Valuable Expert 2018
Distinguished Expert 2018

Commented:
Yep.
Luis DiazIT consultant

Author

Commented:
Thank you.
Bill PrewIT / Software Engineering Consultant
Top Expert 2016

Commented:
To replace a space in the BAT approach, you would do this (there is one space after the equal sign):

set "SourceString= "

not:

set SourceString=" "


»bp
Luis DiazIT consultant

Author

Commented:
Noted. Thank you very much!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial