You have 240 photos named IMG_0001.JPG through IMG_0240.JPG, or a folder of logs called report final (2).txt, and you want sane names. Clicking through Explorer one file at a time is not a plan. Rename-Item with a script block is.
The one-liner that does the real work
Get-ChildItem *.JPG | Rename-Item -NewName { $_.Name -replace '^IMG_', 'trip-2026-' } -WhatIf
What happens here:
-
Get-ChildItem *.JPGsends file objects down the pipeline, not text. -
-NewName { ... }is a delay-bind script block: PowerShell runs it once per file, with$_set to the current file. -
-replaceis a regex replace, so^IMG_only matches at the start of the name. -
-WhatIfprints what would happen. Nothing is renamed yet.
When the preview looks right, run the same line without -WhatIf.
Recipe 1: lowercase extensions
Get-ChildItem -File | Rename-Item -NewName { $_.BaseName + $_.Extension.ToLower() }
BaseName is the name without the extension, so you only touch the .JPG part.
Recipe 2: replace spaces with dashes
Get-ChildItem -File -Filter '* *' | Rename-Item -NewName { $_.Name -replace '\s+', '-' }
Filtering with '* *' first means files without spaces never hit Rename-Item at all, so you avoid "source and destination are the same" errors.
Recipe 3: number files in order
$i = 1
Get-ChildItem *.jpg | Sort-Object LastWriteTime | Rename-Item -NewName {
'photo-{0:D3}{1}' -f $script:i++, $_.Extension
}
{0:D3} pads the number to three digits (photo-001.jpg), so files sort correctly everywhere. Use $script:i because the script block runs in its own scope; a plain $i++ would not keep counting.
Recipe 4: add a date prefix
Get-ChildItem *.log | Rename-Item -NewName { '{0:yyyy-MM-dd}_{1}' -f $_.LastWriteTime, $_.Name }
ISO dates sort alphabetically and chronologically at the same time.
Three traps worth knowing
-
-NewNameis a name, not a path.Rename-Itemcannot move files to another folder. If you want that, useMove-Item. -
Square brackets are wildcards. A file called
report[1].txtneeds-LiteralPath, or pipe it in fromGet-ChildItemlike above, which avoids the problem. -
Collisions stop the rename. If two files would end up with the same name, the second one fails with an error. Always run
-WhatIffirst and read the output.
Why the pipeline version beats a loop
You could write a foreach loop with Rename-Item -Path $f.FullName -NewName .... It works, but the script-block form keeps the filter, the rule, and the preview in one line you can tweak and rerun. That is the habit that makes PowerShell feel faster than a GUI.
Practice it without breaking real files
Bulk renames are exactly the kind of command you want to try somewhere safe first. In CMD Master's interactive PowerShell lessons you can practice pipelines like this in a live browser terminal with instant feedback, no install and no VM. It also covers Windows CMD and Bash if you jump between systems.
Your turn: what's the messiest batch of filenames you've had to fix? Drop the pattern in the comments and I'll suggest a one-liner.
Top comments (0)