No se puede generar mediante programación ParameterSetMetadata Mientras Creación de un bloque de parámetros

StackOverflow https://stackoverflow.com/questions/2466210

Pregunta

Estoy intentando crear mediante programación un bloque de parámetros para una función (en la línea de esta entrada de blog ).

Estoy empezando con un objeto CommandMetadata (de una función existente). Puedo crear el ParameterMetaData objeto y poner las cosas como el ParameterType, el nombre, así como algunos atributos.

El problema que estoy corriendo en es que cuando uso el GetParamBlock método de la clase ProxyCommand, ninguno de mis atributos que puse en la colección de atributos de la ParameterMetaData se generan.

El problema que esto causa es que cuando el GetParamBlock se llama, el nuevo parámetro no está anotado con el atributo de parámetro apropiado.

Ejemplo:

function test 
{
    [CmdletBinding()]
    param (
    [Parameter()]
    $InitialParameter)

    Write-Host "I don't matter."
}

$MetaData = New-Object System.Management.Automation.CommandMetaData (get-command test)

$NewParameter = New-Object System.Management.Automation.ParameterMetadata 'NewParameter'

$NewParameter.ParameterType = [string[]]

$Attribute = New-Object System.Management.Automation.ParameterAttribute 
$Attribute.Position = 1
$Attribute.Mandatory = $true
$Attribute.ValueFromPipeline = $true

$NewParameter.Attributes.Add($Attribute)
$MetaData.Parameters.Add('NewParameter', $NewParameter)


[System.Management.Automation.ProxyCommand]::GetParamBlock($MetaData) 
¿Fue útil?

Solución

function test 
{
    [CmdletBinding()]
    param (
    [Parameter()]
    $InitialParameter)

    Write-Host "I don't matter."
}

$MetaData = New-Object System.Management.Automation.CommandMetaData (get-command test)

$NewParameter = New-Object System.Management.Automation.ParameterMetadata 'NewParameter'

$NewParameter.ParameterType = [string[]]

$Attribute = New-Object System.Management.Automation.ParameterAttribute 
$Attribute.Position = 1
$Attribute.Mandatory = $true
$Attribute.ValueFromPipeline = $true

$NewParameter.Attributes.Add($Attribute)
$MetaData.Parameters.Add('NewParameter', $NewParameter)

$ParameterSetMetadata = "System.Management.Automation.ParameterSetMetadata"
$ParameterSetInfo = new-object psobject -Property @{ 
    Position=[Int]::MinValue
    Flags=3
    HelpMessage="Please Enter a Value"
} | ForEach { 
    $_.PSTypeNames.Add("Deserialized.$ParameterSetMetadata")
    write-Output $_ 
}

$converter = new-object  Microsoft.PowerShell.DeserializingTypeConverter
$ConvertedSet = $converter.ConvertFrom($ParameterSetInfo,$ParameterSetMetadata, $null, $true)

$NewParameter.ParameterSets.Add('__AllParameterSets', $ConvertedSet )

[System.Management.Automation.ProxyCommand]::GetParamBlock($MetaData)

Otros consejos

La razón por la que no aparece es porque su NewParameter tiene que pertenecer a al menos un conjunto de parámetros. En este caso, debe ser un miembro de la ParameterSet especial "__AllParameterSets."

Puede verificar esto copiando el ejemplo ParameterSetMetadata de InitialParameter. Desafortunadamente, no puedo ver inmediatamente cómo conseguir este ParameterSetMetadata si usted no tiene ningún parámetro para captar desde. Copiándolo desde el otro parámetro hace que aparece en la salida, pero es la metadatos de InitialParameter, por lo que esta no es la solución, sólo la razón por la que no funciona (todavía). Voy a actualizar este post cuando yo lo veo a cabo.

-Oisin

diatriba en: Yo era aún muy, muy enojado que podemos crear una instancia de un tipo de System.Management.Automation.ParameterMetadata pero no podemos initialisize ella. Microsoft destruye gran alegría de la biblioteca de clases por contraining las clases mediante el uso de privado o interno o sellada ...... que lo utilizan a menudo, y sin ninguna razón pensable. Esto es un diseño de la biblioteca muy loco! despotricar apagado:

Para metaprogramming y crear ProxyCommands (funciones de proxy) que tenía la necesidad de crear un parámetro de Windows PowerShell mediante programación desde cero. Incluso no desea entrar en las clases y robar y utilizar vorbidden cosas, que está sujeta a cambios. Incluso el truco serialización es la misma manera sucia de hacer lo mismo en una ruta diferente.

aquí está mi prototipo de una solución. Estoy creando una función con un parámetro como texto (código fuente) función. mi primer atempt era hacer una función New-Item: \ -valor {code} en la unidad de función y luego hacer un Get-Command a la nueva función para extraer los metadatos. Pero esto se manifiesta, que la función era una sorcecode muertos único caballo. No se consiguió compilado. Así que tuve que utilizar Invoke-Expression para 'compilación' el código fuente de la función.

Function New-Parameter {

    [CmdletBinding()]
    param(
        [Switch]$Mandatory,
        [UInt32]$Position,
        [Switch]$ValueFromPipeline,
        [Switch]$ValueFromPipelineByPropertyName,
        [Switch]$ValueFromRemainingArguments,
        [String]$HelpMessage,

        [Type]$Type=[Type]'System.Management.Automation.SwitchParameter',
        [Parameter(Mandatory=$True)]
        [String]$Name,
        [String]$DefaultValue,

        [Switch]$DontShow,

        [String[]]$ParameterSetName,
        [String[]]$Aliases,
        # if Metadata is present the result is an System.Management.Automation.ParameterMetadata object
        # If Metadata is absent the sourcecode for the Parameter is returned
        [Switch]$Metadata
    )

    $ParameterAttrib = [System.Collections.ArrayList]@()

    # using GUID to create an unique function Name
    $Guid = ([Guid]::NewGuid()).ToString()

    # using a StringBuilder to glue the sourcecode 
    $stringBuilder = New-Object System.Text.StringBuilder

        If($Metadata.IsPresent) {

        # Open the Function{} block
        [Void]$stringBuilder.AppendLine("Function $Guid {")

        # add the [CmdletBinding()] attribute 
        [Void]$stringBuilder.AppendLine("[CmdletBinding()]")

        # Open the Param() block
        [Void]$stringBuilder.AppendLine("param(")
    } 

    # query if we have one or more ParameterSetName
    $ParmameterSetNameCount = 0
    If(-not [String]::IsNullOrEmpty($ParameterSetName)) {
        $ParmameterSetNameCount = @($ParameterSetName).Count
    } 

    # Open the [Parameter()] attribut
    [Void]$stringBuilder.Append('[Parameter(')

    If($Mandatory.IsPresent) {
        [Void]$ParameterAttrib.Add('Mandatory=$True')
    }
    If($Position) {
        [Void]$ParameterAttrib.Add("Position=$Position")
    }
    If($ParmameterSetNameCount -gt 0){
            # in the first full blown [Parameter()] attribut allways insert the first ParametersetName
            [Void]$ParameterAttrib.Add("ParameterSetName='$($ParameterSetName[0])'")  
    }


    If($ValueFromPipeline.IsPresent) {
        [Void]$ParameterAttrib.Add('ValueFromPipeline=$True')
    }
    If($ValueFromPipelineByPropertyName.IsPresent) {
        [Void]$ParameterAttrib.Add('ValueFromPipelineByPropertyName=$True')
    }
    If($ValueFromRemainingArguments.IsPresent) {
        [Void]$ParameterAttrib.Add('ValueFromRemainingArguments=$True')
    }
    If($DontShow.IsPresent) {
        If($PSVersionTable.PSVersion.Major -lt 4) {
            Write-Warning "The 'DontShow' attribute requires PowerShell 4.0 or above! `n Supressing the 'DontShow' attribute!"
        } Else {
            [Void]$ParameterAttrib.Add('DontShow')
        }

    }
    If(-not [String]::IsNullOrEmpty($HelpMessage)) {
        [Void]$ParameterAttrib.Add("HelpMessage='$HelpMessage'")
    }

    # generate comma separated list from array
    [Void]$stringBuilder.Append("$($ParameterAttrib -Join ',')")

    $ParameterAttrib.Clear()

    # close the [Parameter()] attribut
    [Void]$stringBuilder.AppendLine(")]")
    $ParmameterSetLoopCounter++

    # If we have more then one ParametersetName
    IF($ParmameterSetNameCount -gt 1) {
        # add remaining parameterset names the parameter belongs to
        for ($i = 1; $i -lt $ParmameterSetNameCount; $i++) { 
            [Void]$stringBuilder.AppendLine("[Parameter(ParameterSetName='$($ParameterSetName[$i])')]")  
        }  
    }

    # Create Alias Attribute from Aliases
    If(-not [String]::IsNullOrEmpty($Aliases)) {
        [Void]$stringBuilder.AppendLine("[Alias('$($Aliases -join "','")')]")
    }

    # add Parameter Type
    [Void]$stringBuilder.Append("[$($Type.Fullname)]")

    # add the Parameter Name
    [Void]$stringBuilder.Append("`$$Name")

        If(-not [String]::IsNullOrEmpty($ParameterSetName)) {
        [Void]$stringBuilder.Append("=$DefaultValue")
        }

    If($Metadata.IsPresent) {
        # close the Param() block
        [Void]$stringBuilder.AppendLine()
        [Void]$stringBuilder.AppendLine(')')

        # close the Function block
        [Void]$stringBuilder.AppendLine('}')
    }

    # return the result
    If($Metadata.IsPresent) {
        # if we have to return a ParameterMetadata Object we create a temporary function
        # because you can instatiate a ParameterMetadata Object but most of the Properties are constrained to get only and not to set!

        # Create and 'compile' the function into the function: drive
        Invoke-Expression ($stringBuilder.ToString())

        # from the temporary function we query the the ParameterMetadata and
        # return theParameterMetadata Object
        (Get-Command -Name $Guid -CommandType Function).Parameters.$Name

        # remove the Function from Function: drive
        $Null = Remove-Item Function:\$Guid -Force

    } Else {
        # return the sourcecode of the Parameter
        Write-Output $stringBuilder.ToString()
    }

}

#Example calls:

# without Parametersets
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34 -Metadata

# with Parametersets
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -ParameterSetName 'Snover','Payette' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -ParameterSetName 'Snover','Payette' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34 -Metadata

ESTOY HACIENDO LA DERECHA para construir el PARAMETERSETS?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top