Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Please pardon a noob question, but I've been completely baffled by this one.

I have a "depositor" directory where user-submitted files arrive, and have no control over the incoming file names.

I created a parser in PS which quite successfully moves files (based on file name content) to an appropriate destination.

This works fine EXCEPT when a filename contains either "[" or "]".

Here is the "rename" pre-processor, which fails to actually rename a file containing either of the pesky bracket characters:

 cd $folderpath
 foreach ($i in get-childitem $folderpath) {   
     if ($i.mode.substring(0,1) -ne “d”) {
        $name = $i.name.replace("[","_")
        $name = $name.replace("]","_")
        Write-Host $i -foregroundcolor “blue”       
        Write-Host $name -foregroundcolor “green”  

        Rename-Item $i $name 

     }
 }

This also fails for ren, copy, move and their cmdlet equivalents

Any insight you might be able to provide would be most welcome.

Thanks in advance . . .

share|improve this question
    
work on you escaping-fu: techotopia.com/index.php/… –  hbdgaf Nov 19 '10 at 17:58
    
@aking1012: That works for literals, but not for variables. –  Dennis Williamson Nov 19 '10 at 21:21

3 Answers 3

Unless you use -LiteralPath, square brackets cause real problems with character escaping. The problem comes from PowerShell de-escaping the strings multiple times internally and using special characters for pattern matching. Getting PowerShell to correctly recognize a literal square bracket in a path string is complex.

If you're using single-quote strings, a bracket needs two backticks to escape it. If you're using double-quote strings, a bracket needs four backticks to escape it.

If you're looking for a file named MyFile[1].txt, you need to use either:

'MyFile``[1``].txt'

or:

"MyFile````[1````].txt"

Yes, it's a pain. To see why it does this, you have to know what's going on. It's easy to do that by working backwards.

The wildcard pattern matching Get-ChildItem does means that if it gets [ab].txt as the path, then it will look for files named a.txt and b.txt. So, if we want to match a literal [ab].txt, we have to escape our brackets with the escape character: the backtick. That gives us this as the actual string of characters we want Get-ChildItem to use for the filespec:

`[ab`].txt

However, we have to pass this filespec as a string. That means Get-ChildItem will escape those backticks, but that's not what we want! We want literal backticks. So, we escape the backticks with backticks in our string to make sure Get-ChildItem uses the right filespec:

'``[ab``].txt'

If we want to use double-quoted strings, then we have to escape each backtick again, as the double-q string will de-escape the string. And that's how you end up with this:

"````[ab````].txt"

This is why so many PowerShell functions that take filespecs have the -LiteralPath option.

share|improve this answer

RenameItem doesn't have a -LiteralPath for some stupid reason.*

Move-Item -LiteralPath $i -destination $name

* Excuses from a co-designer of the language.

share|improve this answer
    
Move-Item -LiteralPath $i -destination $name throws this error: Rename-Item : A parameter cannot be found that matches parameter name 'LiteralPath'. –  TTrewitt Nov 19 '10 at 22:36
    
@TTrewitt: What version of PS? –  Dennis Williamson Nov 19 '10 at 22:41
    
The link in this answer has gone 404. Anyone know of a replacement? –  Philip Kendall Jul 18 '13 at 13:01
    
@PhilipKendall: I fixed the link. –  Dennis Williamson Jul 18 '13 at 13:07

This finally achieved the desired result:

foreach ($i in get-childitem $folderpath) {
  if ($i.mode.substring(0,1) -ne “d”) {
    $name = $i.name.replace("[","_")
    $name = $name.replace("]","_")

   Write-Host $name -foregroundcolor “green”    
   [System.IO.File]::Move($folderPath+"\"+$i, $folderPath+"\"+$name) 
  }
}
share|improve this answer

protected by Dennis Jan 26 '13 at 3:40

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.