Copy file with square brackets [ ] in the filename and use * wildcard

In this situation, you have to use double-backticks with single quotes in order to escape the brackets. You can also use quadruple backticks when you use double quoted strings.

So the fixed line of code is:

Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\'``[RoomView``] Versions explained*.pdf' -Destination $FSG\$containerFolder\$rootFolder\'Fusion Server'\

Another good resource on file paths and wired characters etc. is to read this article: Taking Things (Like File Paths) Literally


EDIT

Thanks to @mklement0 for highlighting that the true cause of this
inconsistency is because of a bug currently in
PowerShell
1.
This bug causes escaping of wildcard characters, as well as backticks
with the default -Path parameter to behave differently than other
parameters e.g. the -Include and -Filter parameters.

To expand on @mklement0’s excellent answer, and comments, and other answers below:

To better understand why we need single quotes and two back ticks in this situation; (and to highlight the bug and inconsistencies) let’s run through some examples to demonstrate what is going on:

Get-Item, and associated cmdlets (Get-ChildItem, Copy-Item, etc.), handle the -Path parameter differently when dealing with a combination of escaped wildcard characters and unescaped wildcard characters *at the same time***!

TLDR: The underlying reason that we need a combination of single quotes and double backticks is how the underlying PowerShell provider parses the -Path parameter string for wildcards. It appears to parse it once for the escape characters, and a second time for the evaluation of the wildcard.

Let’s go through some examples to demonstrate this odd outcome:

First, let’s create two files to test with called File[1]a.txt and File[1]b.txt

"MyFile" | Set-Content '.\File`[1`]a.txt'
"MyFriend" | Set-Content '.\File`[1`]b.txt'

We’ll try different ways to get the file. We know that Square brackets [ ] are wildcards, and so we need to escaped them with the backtick character.

We will try to get one file explicitly.

Let’s start by using single quoted literal strings:

PS C:\> Get-Item 'File[1]a.txt'
PS C:\> Get-Item 'File`[1`]a.txt'

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt

PS C:\> Get-Item 'File``[1``]a.txt'

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt

For single quoted strings, one backtick is all that is required to retrieve the file, but two backticks also work.

Using Double quoted strings we get:

PS C:\> Get-Item "File[1]a.txt"
PS C:\> Get-Item "File`[1`]a.txt"
PS C:\> Get-Item "File``[1``]a.txt"

    Directory: C:\  

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt

For double quoted strings, as expected, we can see that we need two backticks to make it work.

Now, we want to retrieve both files and use a wildcard.

Let’s start with single quotes:

PS C:\> Get-Item 'File[1]*.txt'
PS C:\> Get-Item 'File`[1`]*.txt'
PS C:\> Get-Item 'File``[1``]*.txt'

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt
-a----       2019-09-06   5:49 PM             10 File[1]b.txt

With the single quotes, when we have a wildcard character, we need two sets of backticks. One to escape the bracket, and a second backtick to escape the backtick that we used to escape the bracket when the wildcard is evaluated.

Similarly for double quotes:

PS C:\> Get-Item "File[1]*.txt"
PS C:\> Get-Item "File`[1`]*.txt"
PS C:\> Get-Item "File``[1``]*.txt"
PS C:\> Get-Item "File```[1```]*.txt"
PS C:\> Get-Item "File````[1````]*.txt"

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt
-a----       2019-09-06   5:49 PM             10 File[1]b.txt

With double quotes it’s a little more verbose to evaluate with a wildcard. In this case, we need four sets of back ticks. For double quotes we need two backticks to escape the bracket, and another two backticks to escape the escape characters once it comes to evaluation of the star wildcard.


EDIT

As @mklement0 mentions, this behavior with the -Path parameter is inconsistent, and behaves differently than the -Include parameter, where only a single backtick is required to properly escape the brackets. This may be “fixed” in a later version of PowerShell.


1 As of Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.3

Leave a Comment