2

I have a script foo.ps1 and a batch file foo.cmd used to launch the script by double clicking the cmd file in file explorer.

The script accepts a switch parameter, but I don't know how to provide this kind of parameter. Simple parameters are ok.

Foo.ps1:

param(
    [Parameter()]
    [Switch]$MySwitch,
    [Parameter()]
    [string]$Name
)

Write-Host "`$MySwitch : $MySwitch, `$Name : $name"

Foo.cmd:

Powershell -noprofile -NonInteractive -file "%~dp0\foo.ps1" -Name "abc"    

If I call the script with only "Name", it works. But If I specify MySwitch, it stops to work:

Foo2.cmd:

Powershell -noprofile -NonInteractive -File "%~dp0\foo.ps1" -Name "abc" -MySwitch:$false

The error is:

C:\temp\foo.ps1 : Impossible de traiter la transformation d'argument sur le paramètre «MySwitch». Impossible de convertir la valeur «System.String» en type « System.Management.Automation.SwitchParameter». Les paramètres booléens acceptent seulement des valeurs booléennes et des nombres, tels que $True, $False, 1 ou 0.
    + CategoryInfo          : InvalidData : (:) [foo.ps1], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,foo.ps1
3
  • I have worked around this in the past by using a [String] parameter with ValidateSet("Yes","No") (or something similar). Commented Jun 11, 2019 at 22:01
  • 2
    If you omit the -MySwitch parameter at all then it's the same as -MySwitch:$false. On the other side, -MySwitch is the same as -MySwitch:$true. Commented Jun 11, 2019 at 22:06
  • 1
    Another approach: … -command "& '%~dp0\foo.ps1' -Name 'a b c' -MySwitch:$false" i.e. using -command instead of -file. Commented Jun 11, 2019 at 22:25

1 Answer 1

2

In Windows PowerShell, there is no way to pass Boolean values when powershell.exe's
-File parameter is used
- this has has since been corrected in PowerShell (Core) 7, whose CLI is pwsh.exe[1].

Use the workaround that JosefZ recommends:

Use of -Command (-c) instead of -File makes PowerShell treat the arguments as PowerShell source code rather than literal arguments, in which case $false is properly recognized (other CLI parameters omitted for brevity).

powershell -c "& \"%~dp0\foo.ps1\" -Name 'abc' -MySwitch:$false"  

Note:

  • &, the call operator, must be used to invoke the script file, because its path is quoted.

  • PowerShell expects embedded " chars. on the command line to be escaped as \" (not as `" or "", the way it works inside PowerShell).

    • With -Command, if you need to embed a verbatim " inside an embedded \"...\" string, use `\" (sic).
    • While you could enclose the script path in '...' instead, to avoid the need for escaping, such a call would break if the expanded directory file path (%dp0) happens to contain ' chars. itself.
  • For general guidance on when to use -File vs. -Command and the different syntax rules that apply, see this answer.


On a conceptual note:

  • Your code already uses the preferred way to pass Boolean arguments in PowerShell: [switch] parameters (sometimes called flags).

  • Switch parameters imply Boolean values: If a given switch - by name only - is specified (-MySwitch), $true is implied; if it is absent altogether, $false is implied. That is, simply omitting -MySwitch:$false would have solved your problem too.

    • By contrast, [bool]-typed parameters - which invariably require an argument - should be avoided. This post contrasts [bool] with [switch] parameters.
  • While (PowerShell-internally) you (always) can pass an explicit value (as you tried with
    -MySwitch:$false, note the required : separator, a space wouldn't work) - doing so is only required in the following scenarios:

    • In case you want to pass a Boolean value via a variable whose value is determined programmatically.

    • In the rare case that a switch defaults to $true, and you need to override that.

      • For conceptual reasons, defaulting switch parameters to $true is best avoided in user code: if necessary, negate the logic of your switch; an example is Write-Host's -NoNewLine switch.

      • However, some of PowerShell's common parameters are switch parameters, which can in effect default to $true via their preference variable counterparts.


[1] PowerShell (Core) 7 supports the following Boolean values when -File is used: $true, $false, true, false (and also $null, but its interpretation differs situationally: scripts (including with -File) and functions interpret it as $false, whereas cmdlets interpret it as $true(!)).
Note that with -Command - and therefore in all PowerShell code - true and false do not work, but 0 and 1 do.
Unfortunately, if you pass an unsupported value, you get the same error message in all scenarios, which in the -File scenario misleadingly suggests that 0 and 1 work too.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.