PowerShell Function Arguments: Can the First Be the First?

I have an advanced feature in PowerShell that looks something like this:

function Foo { [CmdletBinding] param ( [int] $a = 42, [int] $b ) } 

The idea is that it can be run with two, one or no arguments. However, the first argument, which becomes optional, is the first. Thus, the following scripts can trigger a function:

 Foo ab # the normal case, both a and b are defined Foo b # a is omitted Foo # both a and b are omitted 

However, as a rule, PowerShell tries to fit one argument into a. So I thought about explicitly specifying the position of the arguments, where a will be at position 0 and position b. However, in order to allow only b, I tried to put in a parameter set. But then b will need a different position depending on the set of parameters you are currently using.

Any ideas how to solve this? I would like to keep the parameter names (which are not actually a and b), so using $args is probably the last resort. I could probably define two sets of parameters: one with two required parameters and one with one optional, but I assume that the parameter names in this case should be different, then?

+4
source share
3 answers

Ideas on how to solve this? Not. I have argued for a similar function , where if the parameter at the point of word 0 is connected to the pipeline, the "position" of any further parameters slide down so that you can continue to provide positional parameters instead of resorting to all named parameters. The team thought it would be too confusing for people - with the position of changing parameters. This behavior is a good reason to bind the associated pipeline parameters at the end of your positional parameters. :-)

BTW with advanced features, $ args is not an option. A view like $ _ - it does not apply. Use ValueFromRemainingArguments instead, for example:

  [Parameter(ValueFromRemainingArguments=$true)] $rest 
+5
source

I'm afraid you cannot do this. The closest thing you can get is to name the first argument. The optional unnamed positional argument must be the last in the set.

 function test-optional { [cmdletbinding(defaultparametersetname="SingleOrNone")] param( [parameter( parametersetname="Both", mandatory=$true, position=1)] [int]$A, [parameter( parametersetname="Both", mandatory=$false, position=2)] [parameter( parametersetname="SingleOrNone", mandatory=$false, position=1)] [int]$B ) end { "parameterset: {0}; a: $a; b: $b" -f $pscmdlet.parametersetname, $a, $b } } test-optional 1 # ok test-optional 3 4 # fail test-optional -a 3 4 # ok test-optional -a 1 # ok test-optional -b 1 # ok test-optional -a 1 -b 2 # ok test-optional # ok 
+2
source

You can do this with dynamic parameters (documented in "about_Functions_Advanced_Parameters"), and this is likely to be the "right" solution. But depending on the complexity of your arguments, you can achieve the same effect in several ways.

You can call your function recursively with the correct location of the arguments:

  function ff($a, $b) { if (!$PSBoundParameters.ContainsKey('b')) { ff -b $a; return } # main logic "a: $a" "b: $b" } 

It leads to:

 PS C:\Users\Droj> ff one two a: one b: two PS C:\Users\Droj> ff one a: b: one PS C:\Users\Droj> ff a: b: 

But this does not allow you to define different types or validation of arguments. So, if you need it, another option is to wrap the main logic in a script block and pass the correct parameters based on what is being passed. Something like that:

 function ff() { param($a, $b) $go = { param($a, $b) "a: $a" "b: $b" } if (!$PSBoundParameters.ContainsKey('b')) { &$go -b $a } else { &$go @PSBoundParameters } } 

..., which leads to the same conclusion.

Hope this helps!

0
source

Source: https://habr.com/ru/post/1311392/


All Articles