6

I want to replace all space characters into "_" in names of all subfolders and files. Unfortunately when I type:

Get-ChildItem -recurse -name | ForEach-Object { Rename-Item $_ $_.replace(" ","_") }

Error message:

Rename-Item : Source and destination path must be different. At line:1 char:60 + Get-ChildItem -recurse -name | ForEach-Object { Rename-Item <<<< $_ $.replace(" ","") } + CategoryInfo : WriteError: (PATH_HERE) [Rename-Item], IOException + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

How I should improve this short code?

Emperor XLII
  • 13,014
  • 11
  • 65
  • 75
matandked
  • 1,527
  • 4
  • 26
  • 51

3 Answers3

16

Don't use the Name switch, it outputs only the names of the objects, not their full path. Try this:

Get-ChildItem -Recurse | `
   Where-Object {$_.Name -match ' '} | `
     Rename-Item -NewName { $_.Name -replace ' ','_' }
Shay Levy
  • 121,444
  • 32
  • 184
  • 206
  • Nice. Might want to include Where-Object {$_.Attributes -notmatch 'Directory' } as an additional filter. You can't rename a directory while you're iterating through it. – Michael Blackburn Jun 07 '14 at 02:25
  • 1
    @MichaelBlackburn another trick is to sort the collection by the FullName in descending order. This forces the script to handle all of the child items in a directory before modifying the directory itself. – Michael J. Heier Jan 15 '15 at 22:16
  • Thank you! I've referred to your answer on a couple other related pages. You are the only one to get around the two most common issues. – Modular Aug 04 '19 at 22:05
  • @MichaelJ.Heier Can you maybe suggest an edit with the code for sorting by FullName? – Ivo Merchiers Dec 03 '19 at 10:40
6

The issue here is that if there is no space in the file name the name does not change. This is not supported by Rename-Item. You should use Move-Item instead:

Get-ChildItem -recurse -name | ForEach-Object { Move-Item $_ $_.replace(" ", "_") }

Additionally, in your answer you missed the underscore in $_.replace(...) plus you where replacing spaces with an empty string. Included this in my answer.

Stefan
  • 14,530
  • 4
  • 55
  • 62
  • 5
    Move-Item : The process cannot access the file because it is being used by another process. At line:1 char:58 + Get-ChildItem -recurse -name | ForEach-Object { Move-Item <<<< $_ $_.replace(" ", "_") } + CategoryInfo : WriteError: – matandked Dec 15 '11 at 13:23
  • 1
    @matandked See this answer `Get-ChildItem -Recurse | Where-Object {$_.Name -match ' '} | Rename-Item -NewName { $_.Name -replace ' ','' }` found on https://stackoverflow.com/a/8520172 – Modular Aug 04 '19 at 22:04
  • This is the one that helped me understand that a filter is needed to make sure the name is changed, otherwise you get errors if trying to rename an object to the same name – Ran Lottem May 28 '21 at 13:10
1

Adding a filter worked for me:

Get-ChildItem C:\path-to-directory -Recurse -Filter *foo* | Rename-Item -NewName { $_.name -replace 'foo', 'bar'} -verbose
Shiham
  • 2,114
  • 1
  • 27
  • 36