I'm trying to bulk-rename the files in a folder by adding a prefix to each filename. I ran `Get-ChildItem -File | Rename-Item -NewName { "MYNEWPREFIX_" + $_.BaseName + $_.Extension }` on a folder containing 174 files. Instead of adding the prefix once, most files were renamed repeatedly—some ended up with the prefix added 35 or 36 times. What is causing PowerShell to process the same files over and over, and what is the safest way to prevent that?
3 Answers
In Windows PowerShell 5.1 and earlier, the pipeline can keep discovering files after they've been renamed. Each newly renamed file still matches `Get-ChildItem -File`, so it gets sent through the pipeline again and receives another prefix. Capture the file list before starting the rename: `(Get-ChildItem -File) | Rename-Item -NewName { 'MYNEWPREFIX_{0}' -f $_.Name }`. You can also assign the result to a variable first and then pipe that fixed collection to `Rename-Item`. PowerShell 7 handles this particular enumeration behavior differently.
A good safety measure is to explicitly exclude files that already begin with the prefix, then rename the remaining snapshot of files. For example: `$Path = 'C:whatever'; $Prefix = 'MYNEWPREFIX_'; $Files = Get-ChildItem -File -LiteralPath $Path | Where-Object { $_.Name -notlike "$Prefix*" }; foreach ($File in $Files) { Rename-Item -LiteralPath $File.FullName -NewName ($Prefix + $File.Name) }`. This also makes it easier to show how many files will change and pause for confirmation before doing anything.
Right—`-File` just limits the output to files and excludes directories. `-Directory` is the corresponding option for selecting only directories. Also, use `-LiteralPath` when passing a full path so wildcard characters in a filename aren't interpreted.
The main fix is to take a complete snapshot before renaming. A compact version is `$files = Get-ChildItem -File; $files | Rename-Item -NewName { 'MYNEWPREFIX_' + $_.Name }`. Filtering out an existing prefix is still worthwhile as a belt-and-suspenders guard. The script-block form of `-NewName` is important here because it lets PowerShell evaluate each input file; using a normal expression in the wrong form can leave `$_` unavailable.

That makes sense. I didn't realize `Get-ChildItem -File` was selecting files rather than writing results to a file.