2

Suppose we have the following SwitchTest.ps script

param(
    [switch]$Flag = $false
)

echo "Flag: $Flag"

The following works as expected:

& ".\SwitchTest.ps1" -Flag
Flag: True

However this doesn't

& ".\SwitchTest.ps1" "-Flag"
Flag: False

Furthermore, if we modify SwitchTest.ps to look like this:

param(
    [switch]$Flag = $false,
    [string]$Str = $null
)

echo "Flag: $Flag"
echo "Str: $Str"

We get this expected behavior:

& ".\SwitchTest.ps1" -Flag
Flag: True
Str: 

And this unexpected one:

& ".\SwitchTest.ps1" "-Flag"
Flag: False
Str: -Flag

I tried -Flag true, -Flag $true, -Flag:$true... no cigar. It looks like the switch param is "skipped" when quoted (i.e. when it's a proper string) - why? What do I do if I want to build "-Flag" programmatically?

5
  • 2
    A string is always a string...... If you want to execute a command stored in a string, use iex as @briantist suggested. Commented Mar 22, 2016 at 20:59
  • See if this article helps clear it up: Running Executables in PowerShell. Commented Mar 22, 2016 at 21:02
  • 1
    I feel like this sentence from the docs is what you don't want to here: Because the call operator does not parse the command, it cannot interpret command parameters. I am inclined to side with Briantist. This is not what it is for. Why use the call operator when you should just be able to omit it when calling a script (testing just in case)? Commented Mar 22, 2016 at 21:19
  • What if it was a scriptblock, though. Don't you need to use the call operator then? Commented Mar 22, 2016 at 21:47
  • I understand my mistake now. I was trying to invoke a PS construct using plain strings (I wrongly assumed all parameters boiled down to strings). I needed a PS mechanism for a PS construct (in this case, splatting). Commented Mar 23, 2016 at 13:35

3 Answers 3

4

Your asking a very good question and have set up a very good test case. Let's leave flag without a parameter so it defaults to $Null. When you specify -Flag by itself, PowerShell uses the switch paramater. But, PowerShell interprets "-Flag" as a string and therefore tries to find a parameter that matches a string variable and passes that string (including the - because it is in double quotes) to the parameter that matches [String] type. Lastly, since you sent a string "-Flag" to the string variable, the Flag variable was left to its default value which was $Null or $False. Nice question.

Here's your code you can use to test this out.

#Put this in a script file, e.g. ParamTest.ps1
Flag: False
Str: -Flag

param(
    [switch]$Flag,
    [string]$Str = $null
)

Write-Output "Flag: $Flag"
Write-Output "Str: $Str"

Execute just as you did above:

 & ".\SwitchTest.ps1" "-Flag"

But now that you see how PowerShell assigns passed in parameters, try the following to trigger the Flag parameter as you intended were originally intending to do:

& .\ParamScript.ps1 "-Flag" -Flag
Sign up to request clarification or add additional context in comments.

Comments

3

Forgive me if I am off-base, but if you want to have that flag conditionally set, drop the call operator and just use splatting.

PS M:\Scripts> $params = @{Flag=$true;Str="Bagels"}

PS M:\Scripts> .\switchTest.ps1 @params
Flag: True
Str: Bagels

1 Comment

Beautiful, splatting works even with the call operator (which I like to keep so I have consistent code whether I'm calling a PS script or a "normal" exe).
1

The behavior you're seeing is exactly what I would expect.

If you want to build it programmatically, use Invoke-Expression.

1 Comment

I know iex works, I'm asking why & doesn't and if there's any workaround.

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.