I am new to PowerShell (coming from Bash), and I cannot understand why a path I build sometimes works and others does not:
PS > E:\Installers\wget\wget-win32-1.19.1.exe --version
GNU Wget 1.19.1 built on mingw32.
...OK
PS > $rootPath = E:\Installers
PS > echo ${rootPath}
E:\Installers
PS > dir ${rootPath}\wget\wget-win32-1.19.1.exe
Directory: E:\Installers\wget
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 19/04/2024 15:50 3481920 wget-win32-1.19.1.exe
PS > ${rootPath}\wget\wget-win32-1.19.1.exe --version
At line:1 char:12
+ ${rootPath}\wget\wget-win32-1.19.1.exe --version
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token '\wget\wget-win32-1.19.1.exe' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Why does ${rootPath}
work with dir
and not on its own?
Why does
${rootPath}
work withdir
and not on its own?
This is explained in Argument mode from the about Parsing documentation. In particular, the bullet point:
- Everything else is treated as an expandable string, except metacharacters that still need escaping. See Handling special characters.
So, essentially, the argument passed to dir
(Get-ChildItem
) is interpreted as if it was an expandable string "${rootPath}\wget\wget-win32-1.19.1.exe"
:
$rootPath = 'E:\Installers'
& {param([string] $path) $path } ${rootPath}\wget\wget-win32-1.19.1.exe
# Parameter binding resolves the concatenation as:
# `E:\Installers\wget\wget-win32-1.19.1.exe`
However in your second attempt PowerShell can't determine that what you're trying to do is create a new string by concatenating the variable value ${rootPath}
with the rest of the string \wget\wget-win32-1.19.1.exe
, you need to help it by wrapping the expression in an expandable string and then invoking that path either with dot-sourcing operator .
or call operator &
both detailed in about Operators:
& "${rootPath}\wget\wget-win32-1.19.1.exe" --version
Other alternative could be to use Join-Path
:
& (Join-Path ${rootPath} wget\wget-win32-1.19.1.exe) --version
Or, perhaps invoking the command info instance, here PowerShell auto-resolves the path to winget for you:
& (Get-Command winget) --version