EDIT
As per The Mad Technician's suggestion, I have submitted a bug report for this on the PowerShell UserVoice site: https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/20034763-dynamic-parameters-and-positional-parameters-do-no
ORIGINAL QUESTION
I want to be able to specify positional parameters within a PowerShell function that include both static and dynamic parameters. e.g. I have
function Test-Positional{
[CmdletBinding(PositionalBinding=$false)]
param(
[Parameter(Mandatory=$false,Position=3)][string]$Param4
)
dynamicparam {
$paramDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$paramname1 = "Param1"
$values1 = 'some','list','of','values' #would normally get these dynamically
$attributes1 = new-object System.Management.Automation.ParameterAttribute
$attributes1.ParameterSetName = "__AllParameterSets"
$attributes1.Mandatory = $true
$attributes1.Position = 0
$attributeCollection1 = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection1.Add($attributes1)
$ValidateSet1 = new-object System.Management.Automation.ValidateSetAttribute($values1)
$attributeCollection1.Add($ValidateSet1)
$dynParam1 = new-object -Type System.Management.Automation.RuntimeDefinedParameter($paramname1, [string], $attributeCollection1)
$paramname2 = "Param2"
$values2 = 'another','list','like','before'
$attributes2 = new-object System.Management.Automation.ParameterAttribute
$attributes2.ParameterSetName = "__AllParameterSets"
$attributes2.Mandatory = $true
$attributes2.Position = 1
$attributeCollection2 = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection2.Add($attributes2)
$ValidateSet2 = new-object System.Management.Automation.ValidateSetAttribute($values2)
$attributeCollection2.Add($ValidateSet2)
$dynParam2 = new-object -Type System.Management.Automation.RuntimeDefinedParameter($paramname2, [string], $attributeCollection2)
$paramname3 = "Param3"
$values3 = 'yet','another','list'
$attributes3 = new-object System.Management.Automation.ParameterAttribute
$attributes3.ParameterSetName = "__AllParameterSets"
$attributes3.Mandatory = $true
$attributes3.Position = 2
$attributeCollection3 = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection3.Add($attributes3)
$ValidateSet3 = new-object System.Management.Automation.ValidateSetAttribute($values3)
$attributeCollection3.Add($ValidateSet3)
$dynParam3 = new-object -Type System.Management.Automation.RuntimeDefinedParameter($paramname3, [string], $attributeCollection3)
$paramDictionary.Add($paramname1, $dynParam1)
$paramDictionary.Add($paramname2, $dynParam2)
$paramDictionary.Add($paramname3, $dynParam3)
return $paramDictionary
}
process{
$PSBoundParameters.Param1
$PSBoundParameters.Param2
$PSBoundParameters.Param3
$PSBoundParameters.Param4
}
}
but if I run PS C:\Windows\System32\inetsrv> Test-Positional 'list' 'another' 'yet' 'so'
I get the error:
Test-Positional : Cannot validate argument on parameter 'Param1'. The argument "another" does not belong to the set "some,list,of,values" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again. At line:1 char:20 + Test-Positional list another yet so + ~~~~~~~ + CategoryInfo : InvalidData: (:) [Test-Positional], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Test-Positional
It does not throw this if I remove the Position=3
attribute from the static parameter ($param4), which is fine except then I can't use it as a positional parameter I have to name it directly. I get the same error if I keep Position=3
and remove PositionalBinding=$false
Is it just not possible to have both static and dynamic parameters be positional parameters? Or am I missing something obvious here?