
Batch-Rename Files by Pattern with a Windows Batch Script
Before you run this
This is a cmd.exe batch file that renames files in one folder by find-and-replace: it takes every file matching a mask (say *.txt), swaps a substring in the filename (say draft → final), and renames it. Its purpose is bulk cleanup of filenames — removing a stray word, fixing a prefix, changing a spelling — without you clicking through Explorer.
- Privileges: No administrator rights are needed as long as you own the files and the folder isn't a protected system location. Renaming files under
C:\Windows,C:\Program Files, or another user's profile would need an elevated prompt, and you should not be doing that anyway. Run it as your normal user. - Test first: Read the script before you run it. Point it at a copy of a folder — not the real one — the first time. The version below ships with a dry-run switch turned on by default, so it prints what it would rename and touches nothing until you deliberately flip it off. Use that.
- This changes data, and there is no automatic undo. A batch
rendoes not go into the Explorer "Undo" history — pressing Ctrl+Z in a window later will not reverse it. The rename is done when it's done. It is reversible by hand only if the change is clean (see the Undo section), so treat the first real run with the same care you'd give any bulk operation. - Collisions:
renwill not silently overwrite an existing file — if the target name already exists it errors out. The script checks for that and skips, rather than clobbering. Substring matching in cmd is case-insensitive, soDraft,draft, andDRAFTall match; know that going in.
Assumed environment: Windows 10 or Windows 11, run from cmd.exe (the classic Command Prompt), operating on a single folder, non-recursively. If you'd rather do this in PowerShell, the standard path there is Get-ChildItem piped to Rename-Item -WhatIf — that's a different guide; I'm doing the batch-file way here.
The simplest case: change an extension
If all you want is to change the extension on a batch of files, you don't need a script at all. The built-in ren command takes wildcards:
ren *.jpeg *.jpg
That renames every .jpeg in the current directory to .jpg. It's the right tool when the pattern is a clean extension swap. It gets unreliable the moment you try to do partial-name surgery with wildcards, though — cmd's wildcard rename has genuinely surprising edge behaviour. For anything more than an extension change, use the loop below.
The script: find-and-replace in filenames
Save this as rename-pattern.bat. Edit the five variables at the top, then run it.
@echo off
setlocal enabledelayedexpansion
rem === Settings you edit ===
set "TARGETDIR=C:\path\to\files"
set "FILEMASK=*.txt"
set "FIND=draft"
set "REPLACE=final"
set "DRYRUN=1" rem 1 = preview only, 0 = actually rename
rem === Do not edit below this line ===
pushd "%TARGETDIR%" || (echo Cannot open "%TARGETDIR%" & exit /b 1)
for %%F in (%FILEMASK%) do (
set "OLD=%%~nxF"
rem substring replace: !OLD! with FIND swapped for REPLACE
set "NEW=!OLD:%FIND%=%REPLACE%!"
if not "!OLD!"=="!NEW!" (
if "%DRYRUN%"=="1" (
echo [DRY RUN] "!OLD!" --^> "!NEW!"
) else if exist "!NEW!" (
echo SKIP : "!NEW!" already exists, leaving "!OLD!" alone
) else (
ren "!OLD!" "!NEW!"
echo RENAMED : "!OLD!" --^> "!NEW!"
)
)
)
popd
endlocal
What the non-obvious lines do:
setlocal enabledelayedexpansionlets me read a variable I just set inside the same loop iteration, using!OLD!instead of%OLD%. Without it, the loop would use the value from before the loop started — a classic cmd trap.%%~nxFis the file's name plus extension with any path stripped. In a batch file the loop variable takes%%F; on the command line directly it would be%F.set "NEW=!OLD:%FIND%=%REPLACE%!"is the substitution. cmd's%var:old=new%replaces every occurrence ofoldin the string, not just the first. SoFIND=a,REPLACE=bonbananagivesbbnbnb. Keep yourFINDstring specific.- The
if not "!OLD!"=="!NEW!"guard means files that don't contain the pattern are ignored, so the output only lists what actually changed. pushd/popdmove into and back out of the target folder sorenoperates there.rencannot move a file between folders — it renames in place only.
Run it
Open Command Prompt, cd to wherever you saved it, and:
rename-pattern.bat
With DRYRUN=1 it prints lines like:
[DRY RUN] "q1-draft-report.txt" --> "q1-final-report.txt"
[DRY RUN] "draft-notes.txt" --> "final-notes.txt"
Read that list. If — and only if — every proposed rename is correct, edit the file, set DRYRUN=0, and run it again to commit.
Common variations
- Add or remove a prefix: to strip a leading
IMG_, setFIND=IMG_andREPLACE=(empty). To add a prefix you can't do it with this replace logic; you'd rename toPREFIX_!OLD!instead — that's a one-line change to therenline,ren "!OLD!" "PREFIX_!OLD!", but test it on a copy because it has its own collision cases. - Recurse into subfolders: swap the loop for
for /r "%TARGETDIR%" %%F in (%FILEMASK%) do (...)and useren "%%F" "!NEW!"with the full path. Recursion multiplies the blast radius, so dry-run it hard. - Case sensitivity: cmd's substring replace is case-insensitive and there's no switch to change that. If you need case-sensitive matching, this isn't the right tool — do it in PowerShell.
Verify it worked
List the folder and confirm the names are what you expect:
dir /b "C:\path\to\files"
/b gives bare filenames, one per line, which is easy to eyeball or pipe into a file for a before/after comparison:
dir /b "C:\path\to\files" > after.txt
If you captured a dir /b > before.txt beforehand, fc before.txt after.txt shows exactly what changed.
Undo
There is no automatic rollback. If the change was clean — a simple, unique substring swap with no skipped collisions — you can reverse it by running the same script with FIND and REPLACE swapped. For the example above, set FIND=final and REPLACE=draft, dry-run it, and confirm before committing.
That reversal is only safe when nothing was skipped and the replacement string didn't already occur in the original names. If the output during the real run showed any SKIP lines, or the pattern was ambiguous, do not trust a blind reverse — restore those files from your copy or backup instead. This is exactly why the first run should be against a copy of the folder.
For the official reference on ren, for, and variable substring substitution, see the Windows Commands documentation on Microsoft Learn (search "ren command" and "for command").
Runs enterprise networks and security for a living, and writes Shore Up to turn two decades of hands-on Linux, Windows and mail-server work into guides you can actually use.
More about the author →Was this article helpful?
Tap a star — no sign-in needed.
Be the first to rate this article.
Related guides
Automate Temp and Log Cleanup with a Batch File
This guide builds a Windows batch file that deletes old log files from a folder you name and temporary files from a temp folder, based on how many days ago each file was last modified. Its purpose is to reclaim disk space on a schedule without you having to remember to do it.
Bulk-Rename and Reorganise Files by Date with Bash
I keep ending up with directories that are one flat dumping ground — exported reports, scans, camera dumps — hundreds of files with no order. This guide builds a small bash script that reads each file's modification date, renames it with a YYYY-MM-DD_ prefix, and moves it into DEST/YYYY/MM/ folders. It is safe by default: it prints what it would do and moves nothing until you explicitly tell it to.
Automate Moving AD Users Between OUs From a CSV
This procedure reads a CSV of user accounts and their destination OUs, then moves each account to its target OU with PowerShell's Move-ADObject . Moving a user changes its distinguished name (DN). That matters because anything scoped by DN or OU — Group Policy links, delegated permissions, and OU-based filters — will start or stop applying to the account the moment it moves. The move itself does not delete the account or its group memberships, and it is reversible if you know where the account came from — which is why the script below records the original OU of every user before it touches anything.
Automate Expiring AD Password Notifications with PowerShell
This script reads every enabled AD user's password-expiry date, works out who expires within a window you set (say, the next 14 days), and emails each of those users a reminder. It reads Active Directory and sends mail — it does not change a single account, reset a password, or alter a policy. That makes it low-risk, but it can still misfire loudly: point it at the whole domain with a bad window and you can email hundreds of people at once, so treat the first live run as the dangerous part.




