In questo articolo vedremo come usare i parametri dinamici in PowerShell Universal per offrire un modulo che si adatta all’input dell’utente.
Cosa sono i parametri dinamici
I parametri dinamici consentono di aggiungere nuovi parametri a un cmdlet o a una funzione avanzata in base ai parametri già forniti. Ad esempio, se l’utente indica che il valore di un parametro -AuthenticationType è Credential, può poi aggiungere un parametro -Credential al cmdlet. Anche se in genere è meglio farlo con i set di parametri, a volte serve un po’ più di logica per decidere quali parametri mostrare.
Gli svantaggi dei parametri dinamici sono in genere che sono meno scopribili di quelli statici, perché emergono solo in fase di esecuzione.
Di seguito un esempio di parametri dinamici in uno script PowerShell. I parametri dinamici richiedono di definire manualmente ogni aspetto del parametro: attributi, tipo e nome, poi di aggiungerli tutti a un dizionario da restituire dal blocco 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
}
Moduli dinamici in PowerShell Universal
PowerShell Universal può ispezionare gli script che definiscono parametri dinamici. Così può creare moduli dinamici di cui gli utenti possono avvantaggiarsi. Non sapranno nemmeno che sta usando PowerShell dietro le quinte.
In questo esempio definiremo uno script con una configurazione di parametri dinamici più complessa. Avremo un elenco di selezione per divisione e sistema, e decideranno se mostrare uno o più componenti in base ai loro valori.
Prima definiamo i parametri statici. Ognuno è un insieme di valori possibili nella nostra organizzazione fittizia.
param(
[ValidateSet("Sales", "HR", "Development")]
[string]$Division,
[ValidateSet("Entra ID", "Exchange", "Azure DevOps")]
[string]$System
)
Poi definiremo un blocco DynamicParam e imposteremo la struttura di base dei parametri dinamici.
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
}
Lo script risultante mostra un modulo con i due elenchi a discesa.
Prima aggiungeremo della logica per decidere cosa succede quando si seleziona una divisione. Nella nostra azienda fittizia, le divisioni sono distribuite su alcune località e mostreranno un altro elenco a discesa con i valori possibili per ciascuna divisione.
In base alla divisione selezionata, decideremo quali località sono disponibili e assegneremo un ValidateSetAttribute per imporre alcuni valori possibili.
$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")
}
Possiamo poi aggiungere un parametro Location alla nostra raccolta di parametri runtime.
$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)
Il risultato è che il modulo ora cambia i valori dell’elenco a discesa della località in base alla divisione selezionata.
Infine, aggiungeremo altra logica per controllare sia il parametro di divisione sia quello di sistema e aggiungere un altro parametro al modulo. Possiamo usare lo stesso dizionario di parametri e aggiungervi il nuovo parametro. Questo parametro è definito come booleano anziché come stringa.
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)
}
Il risultato è che il modulo ora si adatta alle modifiche dei parametri di divisione e di sistema.
Dopo aver inserito i parametri nello script ed eseguito, vedrà che i valori dei parametri dinamici vengono passati insieme a quelli statici.
Limiti
I parametri dinamici sono utili, ma hanno un ambito limitato. Questo diventa soprattutto un problema quando vuole adattare i parametri in base al valore dei parametri dinamici stessi. Ad esempio, non potrebbe aggiungere nuovi parametri dinamici in base ai parametri Location o RunPipeline nell’esempio sopra.
I parametri dinamici possono anche ridurre la scopribilità dei parametri in funzioni come il sistema di guida e rendere più difficile capire le funzioni. Le definizioni dei parametri dinamici sono difficili da leggere e possono essere ostiche per gli altri sviluppatori del team.
Valuti di usare i set di parametri invece dei parametri dinamici, quando possibile. In PowerShell Universal, può anche usare le app per definire moduli più solidi e lasciare gli script con parametri statici.
Script
Trova lo script completo di questo articolo di seguito.
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
}
Pronto a iniziare a creare? Scarichi PowerShell Universal.

Adam Driscoll