Assistance with Pipeline handling dynamic parameters with a dynamic validateset

Copper Contributor
I'm writing a module for which I have a function that I want to handle both pipeline and provided
parameters at runtime with one parameter 'prefix' with a dynamic validateset.  On Module load, a
settings hash table is built (Script Scope) from which the function is to load its validateset from

 

I've provided a copy of the working code with a static validateset that works as expected and a copy
attempting to utilize the building of dynamic parameters (based on research from here, here and here) that isn't.
 
Based on feedback/corrections, I would like to Handle missing prefix property by throwing a non-terminating error indicating missing property (and not the hashtable lookup error).

 

#Settings Hashtable
$SettingsHash = @{}

$SettingsHash.Add("Prefix1",[PSCustomObject]@{
  Desc = "Prefix1"
  Prefix = "P1_"
  Option = 1
})
$SettingsHash.Add("Prefix2",[PSCustomObject]@{
  Desc = "Prefix2"
  Prefix = "P2_"
  Option = 123
})

#Works (static validateset collection)
function New-Example {
  [CmdletBinding(DefaultParameterSetName = 'NonPipeline')]
  [OutputType([PSCustomObject])]
  param (
      [Parameter(
        ParameterSetName = 'NonPipeline',
        Mandatory = $true,
        Position = 0,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true
      )]
      [Parameter(
        ParameterSetName = 'Pipeline',
        Mandatory = $true,
        Position = 0,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true
      )]
      [ValidateLength(1,16)]
      [Alias("Computername")]
    [string]$Servername,
      [Parameter(
        ParameterSetName = 'NonPipeline',
        Mandatory = $true,
        Position = 1
      )]
      [Parameter(
        ParameterSetName = 'Pipeline',
        Mandatory = $true,
        Position = 1,
        ValueFromPipelineByPropertyName = $true
      )]
      [ValidateSet("Prefix1","Prefix2")]
    [string]$Prefix
  )

  begin {
    $ParameterName = 'Prefix'
  }

  process {
    foreach ($Server in $Servername) {
      $PrefixSelection = $PsBoundParameters[$ParameterName]
      return [PSCustomObject][ordered]@{

        Servername = ($($SettingsHash.Item($PrefixSelection).prefix) + $Server).ToLower()
        Prefix = $PrefixSelection
      }
    }
  }

  end {

  }
}


#Test Data
$t = @([PSCustomObject]@{
  Servername = "Server1"
  Prefix = "Prefix1"
},
[PSCustomObject]@{
  Servername = "Server2"
  Prefix = "Prefix2"
})
#Tests
> New-Example -Servername blah -Prefix Prefix1

Servername Prefix
---------- ------
p1_blah    Prefix1

###
> "blah","blgr" | New-Example -Prefix Prefix2

Servername Prefix
---------- ------
p2_blah    Prefix2
p2_blgr    Prefix2


###
> $t | New-Example

Servername   Prefix
--------   ------
p1_server1 Prefix1
p2_server2 Prefix2

Here is an attempt with using Dynamic Parameters that doesn't function as expected:

############################################################
#Doesn't Work (dynamic validateset collection)
function New-Example {
  [CmdletBinding(DefaultParameterSetName = 'NonPipeline')]
  [OutputType([PSCustomObject])]
  param (
      [Parameter(
        ParameterSetName = 'NonPipeline',
        Mandatory = $true,
        ValueFromPipeline = $true,
        Position = 0,
        ValueFromPipelineByPropertyName = $true
      )]
      [Parameter(
        ParameterSetName = 'Pipeline',
        Mandatory = $true,
        ValueFromPipeline = $true,
        Position = 0,
        ValueFromPipelineByPropertyName = $true
      )]
      [ValidateLength(1,16)]
      [Alias("Computername")]
    [string[]]$Servername
  )
  DynamicParam {
    # Set the dynamic parameters' name
    $ParameterName = 'Prefix'

    # Create the dictionary
    $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

    # Create the collection of attributes
    $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]

    ###
    # ParameterSet 'NonPipeline'
    ###
    # Create and set the parameters' attributes
    $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
    $ParameterAttribute.Mandatory = $true
    $ParameterAttribute.Position = 1
    $ParameterAttribute.ParameterSetName = 'NonPipeline'


    ###
    # ParameterSet 'Pipeline'
    ###
    # Create and set the parameters' attributes
    $ParameterAttribute1 = New-Object System.Management.Automation.ParameterAttribute
    $ParameterAttribute1.Mandatory = $true
    $ParameterAttribute.Position = 1
    $ParameterAttribute1.ParameterSetName = 'Pipeline'
    $ParameterAttribute1.ValueFromPipelineByPropertyName = $true


    # Add the attributes to the attributes collection
    $AttributeCollection.Add($ParameterAttribute)
    <#$AttributeCollection.Add($ParameterAttribute1)#>

    # Generate and set the ValidateSet
    $arrSet = $SettingsHash.Keys | Sort-Object
    $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)

    # Add the ValidateSet to the attributes collection
    $AttributeCollection.Add($ValidateSetAttribute)

    # Create and return the dynamic parameter
    $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
    $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)

    return $RuntimeParameterDictionary

  }
  begin {
    $ParameterName = 'Prefix'
  }

  process {
    foreach ($Server in $Servername) {
      $PrefixSelection = $PsBoundParameters[$ParameterName]

      return [PSCustomObject][ordered]@{

        Servername = ($($SettingsHash.Item($PrefixSelection).prefix) + $Server).ToLower()
        Prefix = $PrefixSelection
      }
    }
  }

  end {

  }
}

 

Test Results

 

#Tests that work
> New-Example -Servername blah -Prefix Prefix1
> "blah","blgr" | New-Example -Prefix Prefix2

#Test That doesn't work
> $t | New-Example

Exception getting "Item": "Key cannot be null.
Parameter name: key"
At line:83 char:25
+ ...   Servername = ($($SettingsHash.Item($PrefixSelection).prefix) + $Ser ...
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], GetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenGetting



Servername Prefix
---------- ------
server1
Exception getting "Item": "Key cannot be null.
Parameter name: key"
At line:83 char:25
+ ...   Servername = ($($SettingsHash.Item($PrefixSelection).prefix) + $Ser ...
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], GetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenGetting

server2

 

0 Replies