Renaming every .txt to .md, or every .jpeg to .jpg — PowerShell can do this in one line without any loops. Here are the patterns, from the simplest to the most flexible.
The One-Liner
Get-ChildItem -File | Rename-Item -NewName { $_.Name -replace '\.txt$', '.md' }
This renames every file in the current directory whose name ends in .txt, changing the extension to .md. Files with other extensions are left unchanged.
Breaking it down:
Get-ChildItem -File— lists files only (no subdirectories).Rename-Item -NewName { ... }— the script block receives each file object as$_and returns the new name.$_.Name -replace '\.txt$', '.md'— the-replaceoperator uses a regex. The\.escapes the dot (a bare.in regex means “any character”), and$anchors the match to the end of the string so it only touches the extension.
Preview Before Renaming
Add -WhatIf to do a dry run — PowerShell prints what it would rename without touching anything:
Get-ChildItem -File | Rename-Item -NewName { $_.Name -replace '\.txt$', '.md' } -WhatIf
Output:
What if: Performing the operation "Rename File" on target "Item: C:\notes\todo.txt Destination: C:\notes\todo.md".
What if: Performing the operation "Rename File" on target "Item: C:\notes\readme.txt Destination: C:\notes\readme.md".
Always run with -WhatIf first when working on a directory you care about.
Specifying a Path
Run from any directory by passing -Path:
Get-ChildItem -Path 'C:\notes' -File | Rename-Item -NewName { $_.Name -replace '\.txt$', '.md' }
Recursive - All Subdirectories
Add -Recurse to walk the entire tree:
Get-ChildItem -Path 'C:\notes' -File -Recurse | Rename-Item -NewName { $_.Name -replace '\.txt$', '.md' }
Filter First with -Filter
-Filter is faster than -Include because it’s handled by the filesystem rather than PowerShell. Use it when you want to limit which files are even collected:
Get-ChildItem -File -Filter '*.txt' | Rename-Item -NewName { $_.Name -replace '\.txt$', '.md' }
-replace vs .Replace()
The -replace operator is regex-based. The string .Replace() method is a literal find-and-replace:
# Regex - only replaces .txt at the end of the name
$_.Name -replace '\.txt$', '.md'
# Literal - replaces every occurrence of ".txt" anywhere in the name
$_.Name.Replace('.txt', '.md')
For extensions, the regex version is safer: .Replace('.txt', '.md') would also rename a file called notes.txt.backup to notes.md.backup, which is probably not what you want.
Using ForEach-Object for More Control
When you need to do more than just rename — log each operation, skip certain files conditionally, or act on the full path — reach for ForEach-Object:
Get-ChildItem -File -Filter '*.txt' | ForEach-Object {
$newName = $_.Name -replace '\.txt$', '.md'
Rename-Item -Path $_.FullName -NewName $newName
}
This is equivalent to the one-liner but gives you room to add logic inside the block.