Home > Blockchain >  Sets of mutually exclusive parameters in C# Powershell Cmdlets: Why is this ambiguous?
Sets of mutually exclusive parameters in C# Powershell Cmdlets: Why is this ambiguous?

Time:03-16

So I originally asked this for a cmdlet written in PowerShell, see: Ambiguous in Powershell Question

The answer for that question works, but only for PowerShell script cmdlets. So here again is the question, but for C# cmdlets ...

I've been trying to get multiple sets of mutual exclusions to work. I want "Width" mutually exclusive to "WidthReset" and "Height" to be mutually exclusive with "HeightReset".

Help for the C# cmdlet shows:

    Get-ArgTest [-Width <Object>] [-Height <Object>] [<CommonParameters>]
    Get-ArgTest [-Width <Object>] [-HeightReset] [<CommonParameters>]
    Get-ArgTest [-Height <Object>] [-WidthReset] [<CommonParameters>]
    Get-ArgTest [-WidthReset] [-HeightReset] [<CommonParameters>]

Help for the PS cmdlet shows:

PS C:\> .\get-ArgTestPs.ps1 -?
get-ArgTestPs.ps1 [-Width <int>] [-Height <int>] [<CommonParameters>]
get-ArgTestPs.ps1 [-Width <int>] [-HeightReset] [<CommonParameters>]
get-ArgTestPs.ps1 [-Height <int>] [-WidthReset] [<CommonParameters>]
get-ArgTestPs.ps1 -WidthReset -HeightReset [<CommonParameters>]

See the following code.

Now Get-ArgTest -Width 5 seems to be ambiguous.

Why is this different that cmdlets implemented in PowerShell directly?

Example output:

PS C:\> Get-ArgTest -Width 5 -HeightReset
Begin!
HELLO, Width=5, Height=, WidthReset=False, HeightReset=True
PS C:\> Get-ArgTest -Width 5
Get-ArgTest: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.
PS 

The tests:

## Try each combination
# First, just the values
Get-ArgTest                                                            # FAIL
Get-ArgTest -Width 2                                                   # FAIL
                                                                       
Get-ArgTest          -Height 4                                         # FAIL
Get-ArgTest -Width 2 -Height 4                                         
                                                                       
# Values and the opposite reset                                        
Get-ArgTest -Width 2                         -HeightReset              
Get-ArgTest          -Height 4   -WidthReset                           
                                                                       
# The Resets                                                           
Get-ArgTest                      -WidthReset -HeightReset              
Get-ArgTest                      -WidthReset -HeightReset:$False       
Get-ArgTest                      -WidthReset:$False -HeightReset:$True 
                                                                       
Get-ArgTest                      -WidthReset
Get-ArgTest                                  -HeightReset

The C# code is:

[Cmdlet("Get", "ArgTest")]
    [CmdletBinding(DefaultParameterSetName = "A")]
    public class ArgTestCmdlet : PSCmdlet
    {
        [Parameter(ParameterSetName = "A")]
        [Parameter(ParameterSetName = "B")]
        public object Width;

        [Parameter(ParameterSetName = "C")]
        [Parameter(ParameterSetName = "A")]
        public object Height;

        [Parameter(ParameterSetName = "C")]
        [Parameter(ParameterSetName = "D", Mandatory = true)]
        public SwitchParameter WidthReset;

        [Parameter(ParameterSetName = "B")]
        [Parameter(ParameterSetName = "D", Mandatory = true)]
        public SwitchParameter HeightReset;

        // This method gets called once for each cmdlet in the pipeline when the pipeline starts executing
        protected override void BeginProcessing()
        {
            WriteObject("Begin!");
        }

        // This method will be called for each input received from the pipeline to this cmdlet; if no input is received, this method is not called
        protected override void ProcessRecord()
        {
        }

        // This method will be called once at the end of pipeline execution; if no input is received, this method is not called
        protected override void EndProcessing()
        {
            WriteObject($"HELLO, Width={Width}, Height={Height}, WidthReset={WidthReset}, HeightReset={HeightReset}");
        }
    }

CodePudding user response:

The CmdletBinding attribute is for declaring cmdlet-like binding behavior on script cmdlets (or "advanced functions" as they're sometimes called).

For a binary cmdlet you need to specify the default parameter set name in the Cmdlet decorator instead:

[Cmdlet("Get", "ArgTest", DefaultParameterSetName = "A")]
public class ArgTestCmdlet : PSCmdlet
{
    // the rest stays the same ...
}
  • Related