4

I have a function with four parameters, two of which can either be set or not. I'm trying to use Parameter Sets to identify which parameters have been set, but I'm hitting some issues with Parameter Set resolution. These are the four possible Parameter Sets -

  • NeitherErrorObjectOrSplunkData
  • BothErrorObjectAndSplunkData
  • OnlyErrorObject
  • OnlySplunkData

When I test all four Parameter Sets using the example code below, the tests for Only an error object and Only some Splunk data both fail with the following error -

Test-ParameterSets : Parameter set cannot be resolved using the specified named parameters.

From my research it seems that this fails because PowerSehll can't work out whether the Parameter Set should be BothErrorObjectAndSplunkData or OnlyErrorObject/OnlySplunkData, which I can understand.

How can I alter my code to determine which of above Parameter Sets are in use? If it's simply not possible with Parameter Sets, how else can I achieve my goal?


Example code

function Test-ParameterSets
{
    [CmdLetBinding(DefaultParameterSetName="NeitherErrorObjectOrSplunkData")]
    param(
        [Parameter(Mandatory=$true)]
        [Parameter(ParameterSetName="NeitherErrorObjectOrSplunkData")]
        [Parameter(ParameterSetName="BothErrorObjectAndSplunkData")]
        [parameter(ParameterSetName="OnlyErrorObject")]
        [Parameter(ParameterSetName="OnlySplunkData")]

        [String]$Message,
        [parameter(ValueFromPipeline=$true)]
        [Parameter(ParameterSetName="BothErrorObjectAndSplunkData")]
        [parameter(ParameterSetName="OnlyErrorObject")]

        [Object]$ErrorObject,
        [Parameter(ParameterSetName="BothErrorObjectAndSplunkData")]
        [Parameter(ParameterSetName="OnlySplunkData")]

        [String[]]$SplunkData,
        [ValidateSet("ERROR", "WARN", "INFO")]
        [String]$Severity = "ERROR"
    )

    Write-Host "$message -"
    Write-Host "-- Parameter Set: $($PSCmdlet.ParameterSetName)`n"
    return
}

Test-ParameterSets -Message "Neither an error object or an Splunk data"
Test-ParameterSets -Message "Only an error object" -ErrorObject (New-Object -TypeName PSCustomObject)
Test-ParameterSets -Message "Only some Splunk data" -SplunkData "Test"
Test-ParameterSets -Message "Both an error object and Splunk data" -ErrorObject (New-Object -TypeName PSCustomObject) -SplunkData "Test"

Example code output

Neither an error object or an Splunk data -
-- Parameter Set: NeitherErrorObjectOrSplunkData

Test-ParameterSets : Parameter set cannot be resolved using the specified named parameters.
At line:31 char:1
+ Test-ParameterSets -Message "Only an error object" -ErrorObject (New- ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Test-ParameterSets], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Test-ParameterSets

Test-ParameterSets : Parameter set cannot be resolved using the specified named parameters.
At line:32 char:1
+ Test-ParameterSets -Message "Only some Splunk data" -SplunkData "Test ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Test-ParameterSets], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Test-ParameterSets

Both an error object and Splunk data -
-- Parameter Set: BothErrorObjectAndSplunkData

David Gard
  • 11,225
  • 36
  • 115
  • 227

1 Answers1

4

Specify that the $ErrorObject and $SplunkData variables are mandatory for these sets.

This will allow PowerShell to distinguish between the sets if only one is provided, or both.

edited following David Gard's comments

function Test-ParameterSets
{
    [CmdLetBinding(DefaultParameterSetName="NeitherErrorObjectOrSplunkData")]
    param(
        # edit: removed ParameterSetName as belong to all sets so redundant
        [Parameter(Mandatory=$true)]
        [String]$Message,

        # edit: included ValueFromPipeline in the same Parameter declarations
        # as ParameterSetName
        [Parameter(ValueFromPipeline=$true, Mandatory=$true, ParameterSetName="BothErrorObjectAndSplunkData")]
        [parameter(ValueFromPipeline=$true, Mandatory=$true, ParameterSetName="OnlyErrorObject")]
        [Object]$ErrorObject,

        [Parameter(Mandatory=$true, ParameterSetName="BothErrorObjectAndSplunkData")]
        [Parameter(Mandatory=$true, ParameterSetName="OnlySplunkData")]
        [String[]]$SplunkData,

        [ValidateSet("ERROR", "WARN", "INFO")]
        [String]$Severity = "ERROR"
    )

    Write-Host "$message -"
    Write-Host "-- Parameter Set: $($PSCmdlet.ParameterSetName)`n"
    return
}

Test-ParameterSets -Message "Neither an error object or an Splunk data"
Test-ParameterSets -Message "Only an error object" -ErrorObject (New-Object -TypeName PSCustomObject)
Test-ParameterSets -Message "Only some Splunk data" -SplunkData "Test"
Test-ParameterSets -Message "Both an error object and Splunk data" -ErrorObject (New-Object -TypeName PSCustomObject) -SplunkData "Test"

Output

Neither an error object or an Splunk data -
-- Parameter Set: NeitherErrorObjectOrSplunkData

Only an error object -
-- Parameter Set: OnlyErrorObject

Only some Splunk data -
-- Parameter Set: OnlySplunkData

Both an error object and Splunk data -
-- Parameter Set: BothErrorObjectAndSplunkData
G42
  • 9,791
  • 2
  • 19
  • 34
  • 1
    I see I can also remove all parameter set declarations form the `$Message` parameter and it still works - much cleaner. – David Gard Jul 19 '17 at 12:38
  • 1
    Ah, and I've just discovered that doing it this way means that `ValueFromPipeline=$true` has to also be within the same `Parameter` declaration as `Mandatory` and `ParameterSetName`. – David Gard Jul 19 '17 at 12:48
  • @DavidGard Glad to hear it's sorted. Reg removing parameter set declaration: that's true; when no parameter sets are specified the parameter can be used in any set. Didn't know that's the case with `ValueFromPipeLine`; it makes sense as it's possible it is `$true` for one set and `$false` for another. My general practice is to include all relevant arguments within the same `Parameter` declaration. – G42 Jul 19 '17 at 12:51
  • Yep, makes sense to include everything - better to be explicit. Thanks for updating the answer. – David Gard Jul 19 '17 at 13:05