我尝试将 System.ComponentModel.DefaultValueAttribute 添加到 RuntimeDefinedParameter 的 AttributeCollection,但它不起作用..
7 回答
Chrissy 的示例可能是正确的方法,但我无法检索默认值。指定默认值时,$PSBoundParameters 中不存在该参数。
我们应用的“解决方法”是将 $PSBoundParameter["Background"] 绑定到我们想要的默认值。$PSBoundParameters["Background"] = "Transparent"
扩展 Chrissy 的示例:
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
}
正如 Bartek 建议的那样,可以使用 Value 属性,如下面的代码所示
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
}
这里重要的一行是 $background.Value = "Transparent" 其中 $background 是一个 RunTimeDefinedParameter。
对于那些好奇的人。我最初尝试将其用作属性,但 ParameterAttributes 中没有可用的 .Value。
System.Management.Automation.RuntimeDefinedParameter 具有“值”属性,所以我想我会用它来设置默认值。它有点工作(当我调试脚本时,我可以使用 $PSCmdlet.GetDynamicParameters() 看到这个“默认”值)但我没有运气在实际函数中访问它(它在 $pscmdlet.GetDynamicParameters() 调用上“死”了) .
无论如何:当我指定值时,我的函数显示的是绑定值而不是默认值。
不确定它是否有帮助,而且当参数是动态的时,我几乎看不到任何默认值的用例。很想知道你为什么需要它。:)
它不完全是您所需要的,但至少是一个很好的解决方法(需要 PowerShell 3.0):
您可以使用 为所有函数的所有参数设置默认值$PSDefaultParameterValues
。请参阅https://technet.microsoft.com/en-us/library/hh847819.aspx或使用 PowerShell 帮助about_Parameters_Default_Values
。
更新:
我在我的 PowerShell 函数中发现了一个错误Test-DynamicParameter
,这导致了一个错误的结论。下面,在 PowerShell 函数中,我将注释掉错误的行。此外,最后一个示例输出已更改。再次,我将注释更改。
好的,所以回答的每个人在如何设置动态参数的“默认”值方面都是正确的。(剧透警报/tl;博士:没有这样的事情。)现在,让我先说我即将演示的功能是通过 PowerShell 5.1 执行的。以下是我在测试中发现的。
首先,我用来测试动态参数和默认值的函数:
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)"
}
}
}
}
现在执行该函数的一些测试(同样,使用 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:\>
好的,所以我从这个输出中学到了一些东西。一个是我在构造动态参数时尝试使用 (我错了,你可以$PSBoundParameters
它来设置其默认值(为 2000 或 120000)。但是,这不起作用,因为尚未处理参数。$PSBoundParameters
在构造动态参数时使用。)发生的情况是创建了参数,然后绑定了发送到 cmdlet 中的各种参数的值。在指定动态参数的值的情况下,动态参数的Value
属性被更新。那么,从这个意义上说,该Value
属性不是动态参数的默认值;它是参数的值。
因此,在我尝试根据其他(绑定)参数的值设置动态参数的“默认”值的函数中,这不起作用,并且该值 (由于我的编码错误,这是真的。但是一旦更正了代码,这个陈述就是错误的。)120000
始终设置为动态参数的初始值。
好的,但是当我没有指定-RequestTimeout <n>
cmdlet 的调用时,在 cmdlet 中引用会$RequestTimeout
导致 null 值。是什么赋予了?如何获得我在参数上设置的默认值?这很容易。我仍然可以访问$RequestTimeoutParameter
用于构建参数定义的变量。正如您在输出中看到的那样,我将其写出来,您可以看到Value
属性已设置。此外,如果-RequestTimeout <n>
指定,则$RequestTimeoutParameter.Value
使用从命令调用传入的值更新属性。
我希望这对其他人有帮助。
为什么不检查参数是否由用户指定,如果不是,例如在开始块中为参数提供一个值;
function Get-Something {
param()
dynamicparam{
<Definition of dynamic parameter "ThisIsADynamicParam">
}
begin {
if (-not $PSBoundParameters.ContainsKey('ThisIsADynamicParam') {
$PSBoundParameters.Add('ThisIsADynamicParam','DefaultValue')
}
}
}
这可能很明显,但我还没有看到有人特别提到这一点,但如果你结合了fourpastmidnights 的出色解释、chrissy 的初步回答和 Tomas 的聪明建议。
您可以将根据用户提供的输入更改的动态参数的值动态分配给 $PSBoundParameter 字典,从而实现在未指定任何内容时提供可访问的默认值的预期效果,同时在用户输入的事件中更新它假如。
dynamicParam {
if ($Param1 -eq $True) {
#Create Abstract Object
$paramDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
$attributeCollection = New-Object -TypeName System.Collections.ObjectModel.Collection[System.Attribute]
#Define Param attributes
$attribute = New-Object System.Management.Automation.ParameterAttribute
$attribute.Mandatory = $false
$attributeCollection.Add($attribute)
#Create Param
$Name = 'DynamicParam1'
$dynParam = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter($Name, [bool], $attributeCollection)
$dynParam.value = $true
$paramDictionary.Add($Name, $dynParam)
$PSBoundParameters["$name"] = $dynParam.Value
}
$paramDictionary
}
因此,此示例将允许您访问$PSBoundParameters.DynamicParam1
默认值$true
或用户提供的值(如果提供了值)的值。
据我所知,该行$PSBoundParameters["$name"] = $dynParam.Value
必须在“默认”赋值语句之后$dynParam.value = $true
。
这是在 PS 7.1 上测试的