MAIN MENU
Blog de Devolutions

Anuncios, actualizaciones y análisis de Devolutions.

Devolutions PowerShell Universal dynamic forms illustration for the blog.

Crear formularios dinámicos con parámetros dinámicos en PowerShell Universal

PowerShell Universal inspecciona DynamicParam y muestra formularios adaptativos. Añada un ValidateSet de Location según Division, muestre RunPipeline para Development y Azure DevOps, y mantenga parámetros estáticos cuando pueda.

En esta entrada veremos cómo usar parámetros dinámicos en PowerShell Universal para ofrecer un formulario que se adapta a la entrada del usuario.

Qué son los parámetros dinámicos

Los parámetros dinámicos permiten añadir nuevos parámetros a un cmdlet o a una función avanzada según los parámetros ya proporcionados. Por ejemplo, si el usuario indica que el valor de un parámetro -AuthenticationType es Credential, puede añadir a continuación un parámetro -Credential al cmdlet. Aunque a menudo es mejor hacerlo con conjuntos de parámetros, a veces hace falta un poco más de lógica para decidir qué parámetros mostrar.

Las desventajas de los parámetros dinámicos suelen ser que son menos descubribles que los estáticos, porque solo aparecen en tiempo de ejecución.

A continuación hay un ejemplo de parámetros dinámicos en un script de PowerShell. Los parámetros dinámicos exigen definir manualmente cada aspecto del parámetro: los atributos, el tipo y el nombre, y luego añadirlos todos a un diccionario que devuelve el bloque DynamicParam.

[CmdletBinding()]
param(
    [ValidateSet("Credential", "AppToken")]
    [string]$AuthenticationType
)

DynamicParam {
    $paramAttributes = [System.Management.Automation.ParameterAttribute]::new()
    $paramAttributes.Mandatory = $true
    $paramAttributesCollect = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
    $paramAttributesCollect.Add($paramAttributes)
    $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()

    if ($AuthenticationType -eq 'Credential') {
        $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new("Credential", [PSCredential], $paramAttributesCollect)
        $paramDictionary.Add("Credential", $dynParam1)
    }

    if ($AuthenticationType -eq 'AppToken') {
        $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new("AppToken", [SecureString], $paramAttributesCollect)
        $paramDictionary.Add("AppToken", $dynParam1)
    }

    return $paramDictionary
}

Formularios dinámicos en PowerShell Universal

PowerShell Universal puede inspeccionar scripts que definen parámetros dinámicos. Así puede crear formularios dinámicos de los que se beneficien sus usuarios. Ni siquiera sabrán que está usando PowerShell en segundo plano.

En este ejemplo definiremos un script con una configuración de parámetros dinámicos más compleja. Tendremos una lista de selección de división y sistema, y decidirán si se muestra uno o más componentes según sus valores.

Primero definimos los parámetros estáticos. Cada uno es un conjunto de valores posibles en nuestra organización ficticia.

param(
    [ValidateSet("Sales", "HR", "Development")]
    [string]$Division,
    [ValidateSet("Entra ID", "Exchange", "Azure DevOps")]
    [string]$System
)

A continuación definiremos un bloque DynamicParam y prepararemos la estructura básica de los parámetros dinámicos.

DynamicParam {
    $paramAttributes = [System.Management.Automation.ParameterAttribute]::new()
    $paramAttributesCollect = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
    $paramAttributesCollect.Add($paramAttributes)
    $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
    return $paramDictionary
}

El script resultante muestra un formulario con las dos listas desplegables.

PowerShell Universal script form showing Division and System drop-downs.
Parámetros estáticos Division y System en el formulario del script

Primero añadiremos lógica para decidir qué ocurre cuando se selecciona una división. En nuestra empresa ficticia, las divisiones están repartidas en varias ubicaciones y mostrarán otra lista desplegable con los valores posibles de cada división.

Según la división seleccionada, decidiremos qué ubicaciones están disponibles y asignaremos un ValidateSetAttribute para imponer algunos valores posibles.

$paramAttributes = [System.Management.Automation.ParameterAttribute]::new()
$paramAttributes.Mandatory = $true

if ($Division -eq 'Sales') {
    $validateAttribute = [System.Management.Automation.ValidateSetAttribute]::new("Washington DC", "Phoenix", "Chicago")
} elseif ($Division -eq 'HR') {
    $validateAttribute = [System.Management.Automation.ValidateSetAttribute]::new("London", "Seattle", "Orlando")
} elseif ($Division -eq 'Development') {
    $validateAttribute = [System.Management.Automation.ValidateSetAttribute]::new("Madison", "Boise", "Denver")
}

Luego podemos añadir un parámetro Location a nuestra colección de parámetros en tiempo de ejecución.

$paramAttributesCollect = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$paramAttributesCollect.Add($paramAttributes)
$paramAttributesCollect.Add($validateAttribute)

$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new("Location", [string], $paramAttributesCollect)
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add("Location", $dynParam1)

El resultado es que nuestro formulario cambia ahora los valores de la lista desplegable de ubicación según la división seleccionada.

PowerShell Universal form showing a Location drop-down based on the selected division.
Valores de Location que cambian con la división seleccionada

Por último, añadiremos lógica adicional para comprobar los parámetros de división y de sistema y añadir un parámetro más al formulario. Podemos usar el mismo diccionario de parámetros y añadirle el nuevo parámetro. Este parámetro se define como un booleano en lugar de una cadena.

if ($Division -eq 'Development' -and $System -eq 'Azure DevOps') {
    $paramAttributes = [System.Management.Automation.ParameterAttribute]::new()
    $paramAttributesCollect = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
    $paramAttributesCollect.Add($paramAttributes)
    $dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new("RunPipeline", [bool], $paramAttributesCollect)
    $paramDictionary.Add("RunPipeline", $dynParam2)
}

El resultado es que nuestro formulario se adapta ahora a los cambios de los parámetros de división y de sistema.

PowerShell Universal form adding a RunPipeline field for Development and Azure DevOps.
RunPipeline aparece para Development y Azure DevOps

Tras introducir los parámetros en el script y ejecutarlo, verá que los valores de los parámetros dinámicos se pasan junto con los estáticos.

PowerShell Universal job output showing static and dynamic parameter values together.
Valores de parámetros estáticos y dinámicos en la salida del trabajo

Limitaciones

Aunque los parámetros dinámicos son útiles, su alcance es limitado. Esto se convierte sobre todo en un problema cuando quiere ajustar sus parámetros según el valor de los propios parámetros dinámicos. Por ejemplo, no podría añadir nuevos parámetros dinámicos según los parámetros Location o RunPipeline en el ejemplo anterior.

Los parámetros dinámicos también pueden reducir la descubribilidad de los parámetros en funciones como el sistema de ayuda y hacer más difícil entender sus funciones. Las definiciones de parámetros dinámicos son difíciles de leer y pueden resultar duras de seguir para otros desarrolladores de su equipo.

Considere usar conjuntos de parámetros en lugar de parámetros dinámicos, cuando sea posible. En PowerShell Universal, también puede usar apps para definir formularios más robustos y dejar sus scripts con parámetros estáticos.

Script

Puede encontrar el script completo de esta entrada a continuación.

param(
    [ValidateSet("Sales", "HR", "Development")]
    [string]$Division,
    [ValidateSet("Entra ID", "Exchange", "Azure DevOps")]
    [string]$System
)

DynamicParam {
    $paramAttributes = [System.Management.Automation.ParameterAttribute]::new()
    $paramAttributes.Mandatory = $true

    if ($Division -eq 'Sales') {
        $validateAttribute = [System.Management.Automation.ValidateSetAttribute]::new("Washington DC", "Phoenix", "Chicago")
    } elseif ($Division -eq 'HR') {
        $validateAttribute = [System.Management.Automation.ValidateSetAttribute]::new("London", "Seattle", "Orlando")
    } elseif ($Division -eq 'Development') {
        $validateAttribute = [System.Management.Automation.ValidateSetAttribute]::new("Madison", "Boise", "Denver")
    }

    $paramAttributesCollect = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
    $paramAttributesCollect.Add($paramAttributes)
    $paramAttributesCollect.Add($validateAttribute)

    $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new("Location", [string], $paramAttributesCollect)
    $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
    $paramDictionary.Add("Location", $dynParam1)

    if ($Division -eq 'Development' -and $System -eq 'Azure DevOps') {
        $paramAttributes = [System.Management.Automation.ParameterAttribute]::new()
        $paramAttributesCollect = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
        $paramAttributesCollect.Add($paramAttributes)
        $dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new("RunPipeline", [bool], $paramAttributesCollect)
        $paramDictionary.Add("RunPipeline", $dynParam2)
    }

    return $paramDictionary
}

¿Listo para crear? Descargue PowerShell Universal.