Forum Discussion
Josh977
May 19, 2021Copper Contributor
Assistance with Pipeline handling dynamic parameters with a dynamic validateset
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
#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
No RepliesBe the first to reply