17

I have a "depositor" directory where user-submitted files arrive and don't have any control over the incoming file names.

I created a parser in PowerShell 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.

How can I fix this?

2
  • 1
    work on you escaping-fu: techotopia.com/index.php/… Commented Nov 19, 2010 at 17:58
  • 1
    @aking1012: That works for literals, but not for variables. Commented Nov 19, 2010 at 21:21

3 Answers 3

19

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.

Let's say you want to get a file literally named [ab].txt.

The wildcard pattern matching that 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-quoted 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.

8

RenameItem doesn't have a -LiteralPath for some stupid reason (broken link).*

Move-Item -LiteralPath $i -destination $name 

* Excuses from a co-designer of the language.

-LiteralPath appears to have been added.

5
  • Move-Item -LiteralPath $i -destination $name throws this error: Rename-Item : A parameter cannot be found that matches parameter name 'LiteralPath'. Commented Nov 19, 2010 at 22:36
  • @TTrewitt: What version of PS? Commented Nov 19, 2010 at 22:41
  • The link in this answer has gone 404. Anyone know of a replacement? Commented Jul 18, 2013 at 13:01
  • @PhilipKendall: I fixed the link. Commented Jul 18, 2013 at 13:07
  • This answer introduced me to the Literal-Path parameter I needed to use for Set-ACL -LiteralPath that was interpreting [] in the filename as wildcards -- Thanks (Link doesn't work anymore sadly--even on archive.org :( ) Commented May 20, 2021 at 15:59
3

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) } } 
1
  • -LiteralPath option does not work in Powershell version1 (Windows default version), if you are unable to upgrade to a newer Powershell due to workplace restrictions (Admin rights), this is by far the best solution to deal with the square brackets problem. Commented Jan 2, 2021 at 11:28

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.