Question

I call a script: "TestArgs1 xxx -T". From within TestArgs1, I call TestArgs2, trying to pass it the same arguments. If I use: "TestArgs2 @args", switch -T is correctly passed as true. Also if I copy $args to another array and pass it, it works. But if I create my own array first, (in order to modify some arguments), switch -T is passed as false. Why is this? How can I correctly pass the switch argument? See sample code below:

###### TestArgs1
Write-Host "#### pass incoming args ###"
TestArgs2 @args
Write-Host "#### copy incoming args ###"
$a = $args
TestArgs2 @a
Write-Host "#### pass created array ###"
$b = "xxx", "-T"
TestArgs2 @b

###### TestArgs2
function Main {
param ($n, [switch] $t, [switch] $d)
"n = $n"
"t = $t"
}
Main @args

The output of this is the follows:
#### pass incoming args ###
n = xxx
t = True
#### copy incoming args ###
n = xxx
t = True
#### pass created array ###
n = xxx
t = False

When I create my own array and pass the same arguments, t shows up as false.

Was it helpful?

Solution

PowerShell does this because the following two commands behave differently:

Some-Command -Param
Some-Command "-Param"

In the first case, Some-Command is called with a parameter named Param, in the second case Some-Command is called with a positional argument that has the value "-Param".

With a little digging, we can figure out how PowerShell knows the difference.

function foo { $args[0] }
foo -SomeParam | Get-Member -MemberType NoteProperty -Force

After running the above, we see the following output:

TypeName: System.String                                                  

Name                   MemberType   Definition                              
----                   ----------   ----------                              
<CommandParameterName> NoteProperty System.String <CommandParameterName>=SomeParam

We see that PowerShell added a NoteProperty to the value in $args. We can conclude from this that PowerShell is using that NoteProperty when splatting to decide if the value in the array is passed as a value or as a parameter.

So - one solution that I don't recommend - you could add a NoteProperty to your strings that are really parameters. I don't recommend this because it would rely on an undocumented implementation detail.

An alternative solution is to use a function like my foo function to turn a syntactic switch into a value that splats as a parameter. That might look like:

function Get-AsParameter { $args[0] }
$b = "xxx", (Get-AsParameter -T)
TestArgs @b

OTHER TIPS

I ran your script and got the same for all three:

PS C:\> .\TestArgs1.ps1 xxx -T
#### pass incoming args ###
n = xxx
t = False
#### copy incoming args ###
n = xxx
t = False
#### pass created array ###
n = xxx
t = False

Code:

###### TestArgs2
function TestArgs2 {
param ($n, [switch] $t, [switch] $d)
"n = $n"
"t = $t"
}

###### TestArgs1
Write-Host "#### pass incoming args ###"
TestArgs2 @args
Write-Host "#### copy incoming args ###"
$a = $args
TestArgs2 @a
Write-Host "#### pass created array ###"
$b = "xxx", "-T"
TestArgs2 @b
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top