如何设置动态参数的默认值?

时间:2012-06-13 09:59:35

标签: powershell

我尝试将System.ComponentModel.DefaultValueAttribute添加到RuntimeDefinedParameter的AttributeCollection中,但它不起作用..

7 个答案:

答案 0 :(得分:2)

正如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。

答案 1 :(得分:2)

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
}

答案 2 :(得分:1)

System.Management.Automation.RuntimeDefinedParameter具有'Value'属性,所以我想我会用它来设置默认值。它有点工作(当我调试脚本我可以使用$ PSCmdlet.GetDynamicParameters()看到这个'默认'值)但我没有运气在实际函数中访问它(它的执行'死'在$ pscmdlet.GetDynamicParameters()调用)

无论如何:当我指定值时,我的函数显示的是绑定值而不是默认值。

不确定是否有帮助,TBH在参数动态时几乎看不到任何默认值的用例。很想知道你为什么需要它。 :)

答案 3 :(得分:1)

这不完全是您所需要的,但至少是一个很好的解决方法(需要PowerShell 3.0):

您可以使用$PSDefaultParameterValues为所有功能的所有参数设置默认值。请参阅https://technet.microsoft.com/en-us/library/hh847819.aspx或使用about_Parameters_Default_Values上的PowerShell帮助。

答案 4 :(得分:0)

好的,因此回答问题的每个人都正确地设置了动态参数的“默认”值。 (剧透警报/ tl; dr:没有这样的东西。)现在,让我在开头说我要演示的功能是通过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
        $RequestTimeoutParameter.Value = $(if ($PSBoundParameters.UseDynamicParameterDefault1) { 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')) {
                Write-Host "`$RequestTimeout = $RequestTimeout (Bound)"
            } else {
                Write-Host "`$RequestTimeout = $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 {
                Write-Host "`$RequestTimeout = $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
Value         : 120000
IsSet         : True
Attributes    : {__AllAttributes, 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
$RequestTimeout = 3000 (Bound)

PS C:\>

好的,因此我从此输出中学到了一些东西。一种是我在构造动态参数时试图使用$PSBoundParameters来设置其默认值(为2000或120000)。但是,这不起作用,因为尚未处理参数。发生的情况是创建了参数,然后绑定了发送到cmdlet的各种参数的值。如果指定了动态参数的值,则会更新动态参数的Value属性。因此,从这个意义上说,Value属性不是动态参数的默认值,而不是;它是参数的 值。

因此,在我尝试根据其他(绑定)参数的值设置动态参数的“默认”值的函数中,此方法不起作用,并且值120000始终设置为动态参数的初始值。

好的,但是当我没有为cmdlet的调用指定-RequestTimeout <n>时,在cmdlet中引用$RequestTimeout会导致返回空值。是什么赋予了?如何获得我在参数上设置的默认值?这很容易。我仍然可以访问用于建立参数定义的$RequestTimeoutParameter变量。正如您在输出中看到的那样,我将其写了出来,您可以看到Value属性已设置。此外,如果指定了-RequestTimeout <n>,则$RequestTimeoutParameter.Value属性将使用命令调用中传递的值进行更新。

我希望这可以帮助其他人。

答案 5 :(得分:0)

为什么不检查用户是否指定了参数,如果不是,则在begin-block中提供该参数的值;

function Get-Something {
    param()
    dynamicparam{
        <Definition of dynamic parameter "ThisIsADynamicParam">
    }
    begin {
        if (-not $PSBoundParameters.ContainsKey('ThisIsADynamicParam') {
            $PSBoundParameters.Add('ThisIsADynamicParam','DefaultValue')
        }

    }
}

答案 6 :(得分:0)

这可能很明显,但是我还没有看到有人具体提及此事,但是如果您将“四点半”的出色解释,克里斯西的初步答案以及托马斯的巧妙建议结合在一起,就可以了。

可以将动态参数的值(根据用户提供的输入而变化)动态分配给$ 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上进行了测试