1

I have the following snippet of a functions parameters and their sets

function Test {
    [CmdletBinding(DefaultParameterSetName='StringConsole')]

    param (
        [Parameter(Mandatory,
                   ValueFromPipelineByPropertyName,
                   ParameterSetName = 'ObjectFile')]
        [Parameter(Mandatory,
                   ValueFromPipelineByPropertyName,
                   ParameterSetName = 'StringFile')]
        [Alias("PSPath")]
        [ValidateNotNullOrEmpty()]
        [string]
        $Path,

        [Parameter(Mandatory,
                   ValueFromPipeline,
                   ParameterSetName='StringFile',
                   Position = 0)]
        [Parameter(Mandatory,
                   ValueFromPipeline,
                   ParameterSetName='StringConsole',
                   Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Message,

        [Parameter(Mandatory,
                   ValueFromPipeline,
                   ParameterSetName='ObjectFile',
                   Position = 0)]
        [Parameter(Mandatory,
                   ValueFromPipeline,
                   ParameterSetName='ObjectConsole',
                   Position = 0)]
        [ValidateNotNullOrEmpty()]
        [object]
        $Object,
 
        [Parameter(ParameterSetName='StringFile')]
        [Parameter(ParameterSetName='StringConsole')]
        [ValidateSet('Information', 'Verbose', 'Warning', 'Error', 'Object')]
        [string]
        $Severity = 'Information',

        [Parameter(ParameterSetName='StringFile')]
        [Parameter(ParameterSetName='StringConsole')]
        [switch]
        $NoPreamble,

        [Parameter(ParameterSetName = 'StringConsole')]
        [Parameter(ParameterSetName = 'ObjectConsole')]
        [switch]
        $Console
    )

}

If I call the function using

Test 'Hello, World'

it properly uses the StringConsole default parameter set from CmdletBinding

If I call the function using

Test -Message 'Hello, World' -Path C:\SomeFile.txt

It properly uses the StringFile parameter set

But if I call the function using

Test 'Hello, World' -Path C:\SomeFile.txt

I get this error and the function doesn't execute:

Parameter set cannot be resolved using the specified named parameters

The error specifically states it couldn't resolve the parameter set using the NAMED parameters. If a parameter gets bound by position does it not also satisfy the "named" parameter? Or do you have to specifically bind the parameter using the name?

Is there anyway I could design the parameter sets to make my last example work and not throw an error?

6
  • It’s either bound positionally or named, sounds like they aren’t the same. Commented Nov 24, 2022 at 23:28
  • I'm unable to replicate, Test 'Hello, World' -Path C:\SomeFile.txt works well and it uses the StringFile parameter set Commented Nov 24, 2022 at 23:35
  • @SantiagoSquarzon Perhaps it's an issue with the other parameters. I've updated the question with the full set of parameters. Are you able to replicate when using all parameters? Commented Nov 24, 2022 at 23:41
  • Now yes, and the issue is clear, -Message is conflicting with -Object since they're both Position 0 and [object] matches a [string] argument. Remove Position = 0 from your object parameter set and you will see what I mean Commented Nov 24, 2022 at 23:46
  • @SantiagoSquarzon That was it! Didn't even think about the fact that [object] would match a [string]. If you want to add that as an answer I'll mark it as correct. Thanks! Commented Nov 24, 2022 at 23:53

1 Answer 1

2

The logic used for your parameter sets looks perfectly fine but the issue is that you have 2 parameters with Position = 0 (-Message and -Object), normally this wouldn't be a problem but one of them is of the type System.Object and since all objects inherit from this class, no matter what you pass as argument in position 0 it will match this parameter. Since the other parameter on Position = 0 is of type System.String then 'Hello, World' (a string but also an object) matches both parameter sets and the binder has no idea which one did you mean to use.

A very easy way of seeing this, without changing your current code and just adding $PSCmdlet.ParameterSetName to the function's body, would be to pass an integer as positional parameter and everything works as expected:

function Test {
    [CmdletBinding(DefaultParameterSetName='StringConsole')]
    param(
        # same param block here
    )

    'Using: ' + $PSCmdlet.ParameterSetName
}

Test 0 -Path C:\SomeFile.txt # => Using: ObjectFile
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.