'Powershell "A positional parameter cannot be found that accepts argument"

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


Solution 1:[1]

Note:

  • As you point out in your own answer, special quoting requirements apply to choco.exe's /ia parameter.
  • However, since you are using 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 

Solution 2:[2]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 JayG30