I tried to add System.ComponentModel.DefaultValueAttribute to AttributeCollection of RuntimeDefinedParameter, but it does't work..
Chrissy's example is probably the correct way to do it, but I was unable to retrieve the default value. The parameter does not exist in $PSBoundParameters when default value is specified.
The "workaround" we applied was to bind $PSBoundParameter["Background"] to the value we want as default. $PSBoundParameters["Background"] = "Transparent"
Extending Chrissy's example:
DynamicParam {
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$colorlist = [System.Enum]::GetNames([System.Drawing.KnownColor])
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = "__AllParameterSets"
$attributes.Mandatory = $false
# Background color
$validationset = New-Object -Type System.Management.Automation.ValidateSetAttribute -ArgumentList $colorlist
$collection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$collection.Add($attributes)
$collection.Add($validationset)
$background = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("Background", [String], $collection)
$PSBoundParameters["Background"] = "Transparent"
$newparams = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$newparams.Add("Background", $background)
return $newparams
}
As Bartek suggested, the Value property can be used as seen in the code below
DynamicParam {
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$colorlist = [System.Enum]::GetNames([System.Drawing.KnownColor])
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = "__AllParameterSets"
$attributes.Mandatory = $false
# Background color
$validationset = New-Object -Type System.Management.Automation.ValidateSetAttribute -ArgumentList $colorlist
$collection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$collection.Add($attributes)
$collection.Add($validationset)
$background = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("Background", [String], $collection)
$background.Value = "Transparent"
$newparams = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$newparams.Add("Background", $background)
return $newparams
}
The important line here is $background.Value = "Transparent" where $background is a RunTimeDefinedParameter.
For those that are curious. I initial tried to use it as an attribute, but there is no .Value available within ParameterAttributes.
UPDATE:
I found an error in my PowerShell function, Test-DynamicParameter
, which led to an erroneous conclusion. Below, in the PowerShell function, I will comment out the erroneous line. Also, the very last example output has changed. Again, I will annotate the changes.
OK, so everyone who has answered is correct in how to set the "default" value of a dynamic parameter. (Spoiler alert / tl;dr: there's no such thing.) Now, let me preface my answer by saying that the function I'm about to demonstrate was executed via PowerShell 5.1. Below is what I found in my testing.
First, the function I'm using to test dynamic parameters and default values:
function Test-DynamicParameter {
[CmdletBinding()]
Param (
[switch]$UseDynamicParameterDefault2000
)
dynamicparam {
# $RequestTimeout parameter
$attributeCollection = New-Object Collections.ObjectModel.Collection[Attribute]
$attributeCollection.Add((New-Object Management.Automation.ParameterAttribute -Property @{ ParameterSetName = "__AllParameterSets" }))
$attributeCollection.Add((New-Object Management.Automation.ValidateScriptAttribute { $_ -ge 0 }))
$RequestTimeoutParameter = New-Object Management.Automation.RuntimeDefinedParameter RequestTimeout, int, $attributeCollection
# This line uses an incorrect name for the dynamic parameter, which caused
# incorrect results in my original post. The corrected line
# appears below this commented out, incorrect line.
#$RequestTimeoutParameter.Value = $(if ($PSBoundParameters.UseDynamicParameterDefault1) { 2000 } else { 120000 })
$RequestTimeoutParameter.Value = $(if ($PSBoundParameters.UseDynamicParameterDefault2000) { 2000 } else { 120000 })
$dynamicParams = New-Object Management.Automation.RuntimeDefinedParameterDictionary
$dynamicParams.Add('RequestTimeout', $RequestTimeOutParameter)
$dynamicParams
}
process {
$RequestTimeoutParameter | Format-List
if ($PSBoundParameters.ContainsKey('UseDynamicParameterDefault2000')) {
Write-Host "`$PSBoundParameters contains 'RequestTimeout'? $($PSBoundParameters.ContainsKey('RequestTimeout'))"
Write-Host "`$RequestTimeout default: 2000"
if ($PSBoundParameters.ContainsKey('RequestTimeout')) {
# UPDATE: The following line should have used $PSBoundParameters to access the RequestTimeout parameter and has been corrected below
#Write-Host "`$RequestTimeout = $RequestTimeout (Bound)"
Write-Host "`$RequestTimeout = $($PSBoundParameters['RequestTimeout']) (Bound)"
} else {
# UPDATE: To be safe, also access $RequestTimeout here via $PSBoundParameters
#Write-Host "`$RequestTimeout = $RequestTimeout (Default Value)"
Write-Host "`$RequestTimeout = $($PSBoundParameters['RequestTimeout']) (Default Value)"
}
} else {
Write-Host "`$PSBoundParameters contains 'RequestTimeout'? $($PSBoundParameters.ContainsKey('RequestTimeout'))"
Write-Host "`$RequestTimeout default: 120000"
if ($PSBoundParameters.ContainsKey('RequestTimeout')) {
Write-Host "`$RequestTimeout = $($PSBoundParameters['RequestTimeout']) (Bound)"
} else {
# UPDATE: Again, use $PSBoundParameters
#Write-Host "`$RequestTimeout = $RequestTimeout (UnBound, Default Value)"
Write-Host "`$RequestTimeout = $($PSBoundParameters['RequestTimeout']) (UnBound, Default Value)"
}
}
}
}
And now some tests executing the function (again, using PowerShell 5.1):
PS C:\> Test-DynamicParameter
Name : RequestTimeout
ParameterType : System.Int32
Value : 120000
IsSet : True
Attributes : {__AllParameterSets, System.Management.Automation.ValidateScriptAttribute}
$PSBoundParameters contains 'RequestTimeout'? False
$RequestTimeout default: 120000
$RequestTimeout = (Unbound, Default Value)
PS C:\> Test-DynamicParameter -RequestTimeout 3000
Name : RequestTimeout
ParameterType : System.Int32
Value : 3000
IsSet : True
Attributes : {__AllParameterSets, System.Management.Automation.ValidateScriptAttribute}
$PSBoundParameters contains 'RequestTimeout'? True
$RequestTimeout default: 120000
$RequestTimeout = 3000 (Bound)
PS C:\> Test-DynamicParameter -UseDynamicParameterDefault2000
Name : RequestTimeout
ParameterType : System.Int32
### UPDATE: Due to incorrect code, this line was wrong...
### Value : 120000
Value : 2000
IsSet : True
Attributes : {__AllParameterSets, System.Management.Automation.ValidateScriptAttribute}
$PSBoundParameters contains 'RequestTimeout'? False
$RequestTimeout default: 2000
$RequestTimeout = (Default Value)
PS C:\> Test-DynamicParameter -UseDynamicParameterDefault2000 -RequestTimeout 3000
Name : RequestTimeout
ParameterType : System.Int32
Value : 3000
IsSet : True
Attributes : {__AllParameterSets, System.Management.Automation.ValidateScriptAttribute}
$PSBoundParameters contains 'RequestTimeout'? True
$RequestTimeout default: 2000
### UPDATE: This line is incorrect when the PowerShell function is corrected.
### $RequestTimeout = 3000 (Bound)
###
$RequestTimeout = 3000 (Bound)
PS C:\>
OK, so I learned a few things from this output. One is that I was trying to use (I was wrong, you can use $PSBoundParameters
while constructing the dynamic parameter in order to set its default value (to either 2000, or 120000). However, this doesn't work, as the parameters have not yet been processed.$PSBoundParameters
while constructing dynamic parameters.) What happens is the parameter is created, then the values sent into the cmdlet for the various parameters are bound. In the case where a value for the dynamic parameter is specified, the dynamic parameter's Value
property is updated. In this sense, then, the Value
property is not a default value for the dynamic parameter; it's the value for the parameter.
So, in my function where I try to set the "default" value of the dynamic parameter contingent upon the value of other (bound) parameters, this doesn't work and the value (Due to my coding error, this was true. But once the code is corrected, this statement is false.)120000
is always set as the initial value for the dynamic parameter.
OK, but when I don't specify -RequestTimeout <n>
to an invocation of the cmdlet, referring to $RequestTimeout
in the cmdlet results in a null value. What gives? How do I get the default value I set on the parameter? That's easy. I still have access to the $RequestTimeoutParameter
variable I used to build up the parameter definition. And as you can see in the output, I wrote that out and you can see the Value
property is set. Furthermore, when -RequestTimeout <n>
is specified, the $RequestTimeoutParameter.Value
property is updated with the value passed in from the command invocation.
I hope this helps someone else out there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With