Reputation: 79
I'm getting this below error trying to run this code and I'm not sure how to resolve it. Anyone ideas?
$ChocoPackage = "packagename"
$localprograms = choco list --localonly
Start-Process -Wait -FilePath "C:\ProgramData\chocolatey\choco.exe" -ArgumentList "install $ChocoPackage -ia "'/D=C:\Program Files\packagename'" -y"
Start-Process : A positional parameter cannot be found that accepts argument '/D=C:\Program Files\packagename'.
At C:\Program Files\install.ps1:3 char:5
+ Start-Process -Wait -FilePath "C:\ProgramData\chocolatey\choco.ex ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand
Upvotes: 1
Views: 17564
Reputation: 437052
Note:
choco.exe
's /ia
parameter.Start-Process
, it is not the instructions from the linked page for PowerShell that apply in this case, but the ones for cmd.exe
(even though there is no shell involved in this invocation; however, like cmd.exe
, console applications themselves generally only understand "..."
quoting); that is, your -ArgumentList
string must end up containing the following verbatim, which is what the string passed to -ArgumentList
below achieves via embedded "
characters escaped as `"
(""
would work too):"/D=""C:\Program Files\packagename"""
Start-Process -Wait -FilePath "C:\ProgramData\chocolatey\choco.exe" `
-ArgumentList "install $ChocoPackage -ia `"/D=`"`"C:\Program Files\packagename`"`"`" -y"
Only if you call choco.exe
directly from PowerShell do the PowerShell instructions apply ('/D=""C:\Program Files\packagename""'
):
& "C:\ProgramData\chocolatey\choco.exe" install $ChocoPackage -ia '/D=""C:\Program Files\packagename""' -y
As for what you tried:
What you passed to -ArgumentList
was composed of three directly adjoining string literals in the form " a "' b '" c "
, to use a simplified example (i.e., a double-quoted string right next to single-quoted string, right next to another double-quoted string).
However, PowerShell doesn't fully support implicit concatenation of directly adjoining string literals to form a single argument the way that POSIX-compatible shells such as bash
do; doing so results in the strings being passed as separate arguments, which caused your problem (Start-Process
saw extra positional parameters after -ArgumentList
it didn't expect).
To demonstrate the original problem with the simplified example:
PS> Write-Output " a "' b '" c "
a
b
c
That is, Write-Output
received string literals " a "
, ' b '
, and " c "
as 3 separate arguments (as implied by their appearing on their own line each).
Only if the first token is unquoted do you get a single string argument composed of it and subsequent quoted tokens:
# *Single* argument, because `a` is *unquoted*.
PS> Write-Output a' b '" c "
a b c
The same applies even if that first unquoted token is a (non-expression) variable reference (e.g., Write-Output $HOME/'folder 1'/"and more"
; see this answer for more information
If you do need to reliably form a single string argument from a mix of double-quoted (interpolating) and single-quoted (verbatim) string literals, use (...)
, the grouping operator, and the +
operator for explicit string concatenation:
PS> Write-Output (" a " + ' b ' + " c ")
a b c
Upvotes: 2
Reputation: 79
Oh course I figured it out almost immediately after reading the official Chocolatey documentation. Since I'm using powershell you have to be very specific in how you wrap spaces in quotes.
-ia '/yo=""Spaces spaces""'
https://docs.chocolatey.org/en-us/choco/commands/#how-to-pass-options-switches
Pass quotes in arguments: When you need to pass quoted values to to something like a native installer, you are in for a world of fun. In cmd.exe you must pass it like this: -ia "/yo=""Spaces spaces""". In PowerShell.exe, you must pass it like this: -ia '/yo=""Spaces spaces""'. No other combination will work. In PowerShell.exe if you are on version v3+, you can try --% before -ia to just pass the args through as is, which means it should not require any special workarounds.
Upvotes: 0