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.
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.
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.
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.
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.

Adam Driscoll