replace special characters

by willbs at 2013-04-06 11:52:14

actually what started the whole thing is i wanted to replace the underscore with a dash in all file and folder names

Get-ChildItem “H:\MUSIC&quot; -Recurse | <br> Where-Object {$_.Name -match '_' } |
Rename-Item -NewName { $.Name -replace '’,’-’ }

this works fine unless the name has a special character in it like “[” or “]” for example
is there a way to do that so any special character doesn’t cause an error

or do i have to do this
replace this special character “[” with this character “-” in every folder and file name, here is my code that doesn’t work

Get-ChildItem “H:\MUSIC&quot; -Recurse | <br> Where-Object {$_.Name -match '[' } |
Rename-Item -NewName { $.Name -replace ‘[’,’-’ }

i am also interested in deleting this [brackets and words inside brackets]
by coderaven at 2013-04-06 12:46:49
Let me see if I can answer your first question. Doing a little looking, the -replace is a nice feature but may not be the best with the “[” items in the string if it is producing an error for you. Try just doing a .Net string replace method call.
Get-ChildItem "H:\MUSIC&quot; -Recurse | <br> Where-Object {$_.Name -match &#39;_&#39; } |
Rename-Item -NewName ([string]$
.Name).Replace(”", “-”))
Also, be careful using $
and 2 |'s in a row maybe use a foreach loop.
by willbs at 2013-04-06 13:02:05
i had to remove the last ) on line 3 because i get, (i also tried to add it at the beginning)
Unexpected token ‘)’ in expression or statement.
At line:3 char:58

when i rerun, i get
Rename-Item : Cannot bind argument to parameter ‘NewName’ because it is an empty string.
At line:3 char:22
+ Rename-Item -NewName <<<< ([string]$.Name).Replace("”, “-”)
+ CategoryInfo : InvalidData: (:slight_smile: [Rename-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.RenameItemCommand

what is supposed to be in [string]?
by coderaven at 2013-04-06 13:08:09
The second question is a little more difficult. There may be a easier way but this is what comes to mind.
… | Rename-Item ([string]$.Name).Replace(([string]$.Name).SubString(([string]$.Name).indexof("["),([string]$.Name).indexof("]")), “”)
I have not tested that so make sure and test it. What it does it replace the substring starting from the “[” and ending at the “]” with a blank string. Let me know how this goes for you.
by willbs at 2013-04-06 13:36:30
sorry but you have me completely confused
by coderaven at 2013-04-06 14:46:38
Try I usually put the [string] in there to ensure that what I am working with is a string.

Get-ChildItem “H:\MUSIC&quot; -Recurse | <br> Where-Object {$_.Name -match &#39;_&#39; } |
Rename-Item -Path $.FullName -NewName ($.Name).Replace(”", “-”)
by willbs at 2013-04-06 14:52:40
i did try and none it it worked
i want the brackets and the string inside the brackets to be a widcard “[i don’t know what’s in here]” and replace it with nothing ""

Get-ChildItem "H:\MUSIC&quot; -Recurse | <br> Where-Object {$_.Name -match '[*]' } |
Rename-Item ([*]$
.Name).Replace(([]$_.Name).SubString(([]$.Name).indexof("["),([*]$.Name).indexof)) ?("]", “”)
by coderaven at 2013-04-06 15:27:28
… | Rename-Item -Path $.FullName -Newname($.Name).Replace(($.Name).SubString(($.Name).indexof("["),($.Name).indexof("]")), “”)

Let me explain what is going on here so that you can get it working the way you want.

After the -Newname here is the process from inside to outside.
See the section where it says ($
.Name).Substring? When selecting a substring you tell it 2 numbers. The first number is where to start and the second number is where to finish. For each of those numbers needed for the substring, we ask the $.name for the character. The first one, the start of the substring, “[”. The indexof will return the number position of the first “[” found in the name. We do the same thing to get the end of the section of the string we want to replace getting the indexof “]”. Now with the index of where “[” and “]” are in the name, we have a substring that would be exactly what we want to replace. This text we want to replace in the substring now is exactly like the replacement of the "" to “-” but we put in the substring and “” to have it removed.

Does that make since?
by willbs at 2013-04-06 15:46:38
i understand i just can’t get it to work, when i run this,

Get-ChildItem “H:\MARK MUSIC&quot; -Recurse | <br> Rename-Item -Path $_.FullName -Newname($_.Name).Replace(($_.Name).SubString(($_.Name).indexof(&quot;[&quot;),($_.Name).indexof(&quot;]&quot;)), &quot;&quot;)<br><br>i get this<br><br>You cannot call a method on a null-valued expression.<br>At line:2 char:98<br>+ Rename-Item -Path $_.FullName -Newname($_.Name).Replace(($_.Name).SubString(($_.Name).indexof &lt;&lt;&lt;&lt; (&quot;[&quot;),($_.Name).indexof(&quot;]&quot;)), &quot;&quot;)<br> + CategoryInfo : InvalidOperation: (indexof:String) [], RuntimeException<br> + FullyQualifiedErrorId : InvokeMethodOnNull</blockquote>by mjolinor at 2013-04-06 22:02:26<blockquote>This:<br><br>[quote]Get-ChildItem &quot;H:\MUSIC\&quot; -Recurse |
Where-Object {$.Name -match ‘[*]’ } | [/quote]<br><br>isn't producing the expected result because the argument to a -match operation is a regular expression, not a wildcard match. In a regex '[*]' designates a character class, containing the character '*'. In other words you've told it to match any filename that has an asterisk in it. <br><br>To match a string consisting of square brackets and all the characters in between, the regex would look like: '\[.+\]'<br>The backslashes escape the square brackets so they're treated literally and not as regex metacharacters. The .+ includes one or more of any character in between.</blockquote>by willbs at 2013-04-07 09:15:31<blockquote>thanks for regex command, i tied to run it 2 ways<br><br>when i run this<br><br>Get-ChildItem &quot;H:\MARK MUSIC\&quot; -Recurse |
Where-Object {$
.Name -match ‘[.+]’ } | <br> Rename-Item -NewName { $_.Name -replace '\[.+\]','-' }<br><br><br>i get this<br><br>Rename-Item : Cannot rename because item at 'Microsoft.PowerShell.Core\FileSystem::H:\MARK MUSIC\Depeche Mode\The Singles 86-98 (pd)\11 - Everything Counts [Live].mp3' does not exist.<br>At line:3 char:17<br>+ Rename-Item &lt;&lt;&lt;&lt; -NewName { $_.Name -replace '\[.+\]','-' }<br> + CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException<br> + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand<br><br>when i run this<br><br>Get-ChildItem &quot;H:\MARK MUSIC\&quot; -Recurse |
Where-Object {$.Name -match ‘[.+]’ } | `
Rename-Item -Path $
.FullName -NewName ($.Name).Replace(’[.+]’, ‘-’)

i get this

You cannot call a method on a null-valued expression.
At line:4 char:58
+ Rename-Item -Path $
.FullName -NewName ($.Name).Replace <<<< ("”, “-”)
+ CategoryInfo : InvalidOperation: (Replace:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
by mjolinor at 2013-04-07 13:41:29
Those square brackets can cause problems in file paths. Does it work better if you use the -LiteralPath parameter on Rename-Item?

Get-ChildItem "H:\MARK MUSIC&quot; -Recurse |
Where-Object {$.Name -match ‘[.+]’ } |
foreach {
Rename-Item -LiteralPath $
.FullName -NewName { $.Name -replace ‘[.+]’,’-’ }
by willbs at 2013-04-07 17:51:28
when i ran that code i get

Rename-Item : Cannot evaluate parameter ‘NewName’ because its argument is specified as a script block and there is no input. A script block cannot be evaluated wit
hout input.
At line:4 char:56
+ Rename-Item -LiteralPath $
.FullName -NewName <<<< { $.Name -replace ‘[.+]’,’-’ }
+ CategoryInfo : MetadataError: (:slight_smile: [Rename-Item], ParameterBindingException
+ FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.PowerShell.Commands.RenameItemCommand
by mjolinor at 2013-04-07 17:55:25
Try a subexpression instead of the script block:

.Name -replace ‘[.+]’,’-’)
by willbs at 2013-04-07 19:14:59
when i did that, i got this

Rename-Item : A parameter cannot be found that matches parameter name ‘LiteralPath’.
At line:4 char:35
+ Rename-Item -LiteralPath <<<< $.FullName -NewName $($.Name -replace ‘[.+]’,’-’)
+ CategoryInfo : InvalidArgument: (:slight_smile: [Rename-Item], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.RenameItemCommand
by mjolinor at 2013-04-07 19:48:52
What version of Powershell are you using? They added support for “blobbing” in filespecs that allowed wildcards, using the [] characters to designate the characters in the “blob” IN V2. Unfortunately the [] are also valid characters in a filename, and some of the cmdlets lacked a -LiteralPath parameter to suppress it for files that had the square brackets as part of the filename. They corrected that in V3.
by willbs at 2013-04-07 20:54:58
i have v2, i’ll update to v3 and give it a try
by willbs at 2013-04-07 21:42:53
ok updated to v3 and ran this

Get-ChildItem "H:\MARK MUSIC&quot; -Recurse |
Where-Object {$.Name -match ‘[.+]’ } |
foreach {
Rename-Item -LiteralPath $
.FullName -NewName $($.Name -replace ‘[.+]’,’-’)

and got this

Rename-Item : Cannot create a file when that file already exists.
At line:4 char:11
+ Rename-Item -LiteralPath $
.FullName -NewName $($_.Name -replace '[.+ …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (H:\MARK MUSIC\J…nnon] [CD2].jpg:String) [Rename-Item], IOException
+ FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand
by mjolinor at 2013-04-08 04:19:40
You’re getting a little farther each time. This is good.

So, it appears you already have a file there with the same name as what you’re trying to rename that file to.

Now you need to decide how you want the script to handle that situtation.
by willbs at 2013-04-08 19:50:21
it’s throwing that error but it did work after checking it

by MasterOfTheHat at 2013-04-09 06:33:07
The next step is like mjolinor suggested; try adding try/catch/finally blocks to the code to handle the IOException. That way your script does something graceful when it encounters the error instead of just bleeding on the screen.