5

I am trying to include a script inside another which is in the same folder, using the dot syntax:

. '.\BaseScript.ps1'

The path to the scripts has a folder with square brackets in the name. Even though I am using relative paths, the path error still occurs.

Moving it to some other path without special characters in the name works fine.

How can such a case be catered while using relative paths?

Umair Ahmed
  • 2,420
  • 1
  • 21
  • 40
  • Cannot reproduce (tried in `PowerShell.exe` and `powershell_ise.exe` `5.1.19041.1151` as well as in `pwsh.exe` `7.1.2`) and with bizarre combinations of square brackets in paths… – JosefZ Aug 11 '21 at 17:10

3 Answers3

7

Unfortunately, PowerShell treats the operands to the . dot-sourcing and & call operators (which includes implicit invocation[1] ) as wildcard expressions, which causes problems with paths that contain [, which is a wildcard metacharacter.

The solution is to escape the [ as `[; e.g., to dot-source a script whose path is ./test[1]/script.ps1:

# Note: '/' and '\' can be used interchangeably in PowerShell.
. ./test`[1]/script.ps1

Important: If the path is relative, it must start with ./ or .\ (see below for full paths).

Note: [ is a wildcard metacharacter, because you can use it to express character ranges ([a-z]) or sets ([56]); while ] is clearly also needed, it is sufficient to escape [.

This unfortunate requirement, which also affects other contexts, is the subject of GitHub issue #4726.


Alternatively - and bizarrely - as Theo's helpful answer shows, the need for this escaping goes away if you use a full path.

# Dot-source 'script.ps1` from the same location as the running
# script ($PSScriptRoot).
# (Use $PWD to refer to the *currrent* dir.)
# Because this results in a *full* path, there is no need to escape, strangely.
. $PSScriptRoot/script.ps1

[1] &, which can invoke any command and runs commands written in PowerShell code in a child scope, isn't strictly needed for invocation; e.g. & ./path/to/script.ps1 and ./path/to/script.ps1 are equivalent; however, & is required if the path is quoted and/or contains variable references - see this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I didn't realize this was due to evaluation as a wildcard expression. How are the `[]` used in wildcard expressions in PowerShell? I thought we were limited to the `*` and `?` globbing characters. – codewario Aug 11 '21 at 14:43
  • 1
    I didn't know wildcard expressions in PowerShell worked with character ranges similar to `bash`. TIL, thanks! – codewario Aug 11 '21 at 14:57
  • 1
    Glad to hear it, @BendertheGreatest. Yes, you don't see it often. Note that `Get-ChildItem`'s `-Filter` parameter does _not_ support these ranges, however, because it isn't PowerShell but the file-system APIs processing the expression. – mklement0 Aug 11 '21 at 14:59
6

The way around this seems to be using a complete path to the second script:

. (Join-Path -Path $PSScriptRoot -ChildPath 'SecondScript.ps1')
Theo
  • 57,719
  • 8
  • 24
  • 41
  • `Join-Path -LiteralPath $PSScriptRoot ...`, (passing the path to `-Path` will result in wildcard globbing) – Mathias R. Jessen Aug 11 '21 at 14:38
  • 2
    @MathiasR.Jessen Join-Path doesn't have a `-LiteralPath` parameter.. (tested and works) – Theo Aug 11 '21 at 14:39
  • 1
    Indeed, Theo. @MathiasR.Jessen, `Join-Path` doesn't have a `-LiteralPath` parameter because it doesn't _need_ one: it is purely a string operation, no wildcard resolution is ever involved. – mklement0 Aug 11 '21 at 15:17
2

@Theo has a useful workaround, but the cause is that [] must be escaped in paths.

$path = 'C:\path\`[to`]\script.ps1'
codewario
  • 19,553
  • 20
  • 90
  • 159