Paramètres PowerShell: Libérez la Puissance du Scripting

Toutes les commandes PowerShell peuvent avoir un ou plusieurs paramètres, parfois appelés arguments. Si vous n’utilisez pas les paramètres PowerShell dans vos fonctions PowerShell, vous n’écrivez pas un bon code PowerShell !

Dans cet article, vous allez apprendre pratiquement tous les aspects de la création et de l’utilisation des paramètres ou arguments PowerShell !

Ceci est un extrait de mon livre PowerShell pour les administrateurs système. Si vous voulez apprendre PowerShell ou découvrir quelques astuces du métier, consultez-le !

Pourquoi avez-vous besoin d’un paramètre ?

Lorsque vous commencez à créer des fonctions, vous avez la possibilité d’inclure des paramètres ou non, et de définir comment ces paramètres fonctionnent.

Disons que vous avez une fonction qui installe Microsoft Office. Peut-être qu’elle appelle l’installateur d’Office en mode silencieux à l’intérieur de la fonction. Peu importe ce que fait la fonction pour nos besoins. La fonction de base ressemble à ceci, avec le nom de la fonction et le bloc de script.

function Install-Office {
    ## exécuter l'installateur silencieux ici
}

Dans cet exemple, vous avez simplement exécuté Install-Office sans paramètres et il fait son travail.

Il n’a pas importé si la fonction Install-Office avait des paramètres ou non. Apparemment, elle n’avait pas de paramètres obligatoires ; sinon, PowerShell ne nous aurait pas permis de l’exécuter sans utiliser de paramètre.

Quand utiliser un paramètre PowerShell

Office a de nombreuses versions différentes. Peut-être avez-vous besoin d’installer Office 2013 et 2016. Actuellement, vous n’avez aucun moyen de spécifier cela. Vous pourriez changer le code de la fonction à chaque fois que vous voudriez changer le comportement.

Par exemple, vous pourriez créer deux fonctions distinctes pour installer différentes versions.

function Install-Office2013 {
    Write-Host 'I installed Office 2013. Yippee!'
}

function Install-Office2016 {
    Write-Host 'I installed Office 2016. Yippee!'
}

Cela fonctionne, mais ce n’est pas évolutif. Cela vous force à créer une fonction distincte pour chaque version d’Office qui sort. Vous serez obligé de dupliquer beaucoup de code alors que ce n’est pas nécessaire.

Au lieu de cela, vous avez besoin d’un moyen de passer des valeurs différentes au moment de l’exécution pour modifier le comportement de la fonction. Comment faites-vous cela ?

Oui ! Des paramètres ou ce que certaines personnes appellent des arguments.

Puisque nous aimerions installer différentes versions d’Office sans changer le code à chaque fois, vous devez ajouter au moins un paramètre à cette fonction.

Avant de penser rapidement à un paramètre PowerShell à utiliser, il est essentiel de vous poser d’abord une question : « Quel est le plus petit changement ou les changements que vous prévoyez devoir apporter à cette fonction ? ».

Rappelez-vous que vous devez exécuter à nouveau cette fonction sans modifier le code à l’intérieur de la fonction. Dans cet exemple, le paramètre est probablement clair pour vous ; vous devez ajouter un paramètre Version. Mais, lorsque vous avez une fonction avec des dizaines de lignes de code, la réponse ne sera pas trop évidente. Tant que vous répondez à cette question aussi précisément que possible, cela vous aidera toujours.

Donc, vous savez que vous avez besoin d’un paramètre Version. Et maintenant ? Vous pouvez maintenant en ajouter un, mais comme tout bon langage de programmation, il existe plusieurs façons de faire cela.

Dans ce tutoriel, je vais vous montrer la « meilleure » façon de créer des paramètres basée sur près d’une décennie d’expérience avec PowerShell. Cependant, sachez que ce n’est pas la seule façon de créer un paramètre.

Il existe ce qu’on appelle des paramètres positionnels. Ces paramètres vous permettent de passer des valeurs aux paramètres sans spécifier le nom du paramètre. Les paramètres positionnels fonctionnent mais ne sont pas considérés comme une « meilleure pratique ». Pourquoi ? Parce qu’ils sont plus difficiles à lire, surtout lorsque vous avez de nombreux paramètres définis sur une fonction.

Création d’un simple paramètre PowerShell

La création d’un paramètre sur une fonction nécessite deux composants principaux : un bloc param et le paramètre lui-même. Un bloc param est défini par le mot-clé param suivi d’un ensemble de parenthèses.

An example of a param block
function Install-Office { [CmdletBinding()] param() Write-Host 'I installed Office 2016. Yippee!' }

À ce stade, la fonctionnalité réelle de la fonction n’a pas changé d’un iota. Nous avons simplement assemblé quelques éléments de base, nous préparant pour le premier paramètre.

Une fois que nous avons le bloc param en place, vous allez maintenant créer le paramètre. La méthode que je vous suggère de créer un paramètre inclut le bloc Parameter, suivi du type de paramètre, puis du nom de la variable du paramètre ci-dessous.

An example of a param block
function Install-Office { [CmdletBinding()] param( [Parameter()] [string]$Version ) Write-Host 'I installed Office 2016. Yippee!' }

Nous avons maintenant créé un paramètre de fonction dans PowerShell, mais que s’est-il exactement passé ici ?

Le bloc Parameter est une partie facultative mais recommandée de chaque paramètre. Comme le bloc param, c’est de la « plomberie de fonction » qui prépare le paramètre pour l’ajout de fonctionnalités supplémentaires. La deuxième ligne est l’endroit où vous définissez le type de paramètre qu’il s’agit.

Dans ce cas, nous avons choisi de convertir le paramètre Version en chaîne de caractères. Le fait de définir explicitement un type signifie que toute valeur passée à ce paramètre sera toujours « convertie » en chaîne de caractères si elle ne l’est pas déjà.

Le type n’est pas obligatoire mais est fortement recommandé. Définir explicitement le type de paramètre permet de réduire considérablement de nombreuses situations indésirables à l’avenir. Faites-moi confiance.

Maintenant que vous avez défini le paramètre, vous pouvez exécuter la commande Install-Office avec le paramètre Version en lui passant une chaîne de caractères de version comme 2013. La valeur passée au paramètre Version est parfois appelée arguments ou valeurs des paramètres.

Passing a Parameter to the Function
PS> Install-Office -Version 2013 I installed Office 2016. Yippee!

Qu’est-ce qui se passe ici de toute façon ? Vous lui avez dit que vous vouliez installer la version 2013, mais il vous dit toujours qu’il a installé la version 2016. Lorsque vous ajoutez un paramètre, vous devez alors penser à modifier le code de la fonction en une variable. Lorsque le paramètre est passé à la fonction, cette variable sera étendue pour être la valeur qui a été passée.

Modifiez le texte statique de 2016 et remplacez-le par la variable du paramètre Version et convertissez les guillemets simples en guillemets doubles afin que la variable puisse être étendue.

Modifying function code account for a parameter
function Install-Office { [CmdletBinding()] param( [Parameter()] [string]$Version ) Write-Host "I installed Office $Version. Yippee!" }

Maintenant, vous pouvez voir que quelle que soit la valeur que vous passez au paramètre Version, elle sera ensuite transmise à la fonction sous la forme de la variable $Version.

L’attribut de paramètre obligatoire.

Rappelez-vous que j’ai mentionné que la ligne [Parameter()] était simplement une « plomberie de fonction » et qu’elle devait préparer la fonction pour un travail ultérieur ? Ajouter des attributs de paramètre à un paramètre est le travail supplémentaire dont je parlais plus tôt.

A parameter doesn’t have to be a placeholder for a variable. PowerShell has a concept called parameter attributes and parameter validation. Parameter attributes change the behavior of the parameter in a lot of different ways.

Par exemple, l’un des attributs de paramètre les plus courants que vous allez définir est le mot-clé Mandatory. Par défaut, vous pourriez appeler la fonction Install-Office sans utiliser le paramètre Version et elle s’exécuterait très bien. Le paramètre Version serait facultatif. Certes, il n’étendrait pas la variable $Version à l’intérieur de la fonction car il n’y avait pas de valeur, mais elle s’exécuterait quand même.

Souvent, lors de la création d’un paramètre, vous voudrez que l’utilisateur utilise toujours ce paramètre. Vous compterez sur la valeur du paramètre à l’intérieur du code de la fonction quelque part, et si le paramètre n’est pas transmis, la fonction échouera. Dans ces cas, vous voulez obliger l’utilisateur à transmettre cette valeur de paramètre à votre fonction. Vous voulez que ce paramètre devienne obligatoire.

Forcer les utilisateurs à utiliser un paramètre est simple une fois que vous avez construit le cadre de base comme vous l’avez fait ici. Vous devez inclure le mot-clé Mandatory à l’intérieur des parenthèses du paramètre. Une fois que vous avez cela en place, l’exécution de la fonction sans le paramètre interrompra l’exécution jusqu’à ce qu’une valeur ait été saisie.

Using a mandatory parameter
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Version ) Write-Host "I installed Office $Version. Yippee!" } PS> Install-Office cmdlet Install-Office at command pipeline position 1 Supply values for the following parameters: Version:

La fonction attendra que vous spécifiiez une valeur pour le paramètre Version. Une fois que vous l’avez fait et que vous appuyez sur Entrée, PowerShell exécutera la fonction et continuera. Si vous fournissez une valeur pour le paramètre, PowerShell ne vous demandera pas le paramètre à chaque fois.

Attributs de validation des paramètres PowerShell

Rendre un paramètre obligatoire est l’un des attributs de paramètre les plus courants que vous pouvez ajouter, mais vous pouvez également utiliser des attributs de validation des paramètres. En programmation, il est toujours essentiel de restreindre au maximum les entrées utilisateur. Limiter les informations que les utilisateurs (ou même vous-même !) peuvent transmettre à vos fonctions ou scripts éliminera le code inutile à l’intérieur de votre fonction qui doit tenir compte de toutes sortes de situations.

Apprendre par l’exemple

Par exemple, dans la fonction Install-Office, j’ai montré comment lui passer la valeur 2013 parce que je savais que cela fonctionnerait. J’ai écrit le code ! Je suppose (ne faites jamais cela dans le code !) qu’il est évident que quiconque sait quelque chose spécifiera la version comme étant soit 2013, soit 2016. Eh bien, ce qui est évident pour vous ne l’est peut-être pas pour d’autres personnes.

Si vous voulez être technique à propos des versions, il serait probablement plus précis de spécifier la version 2013 comme étant 15.0 et 2016 comme étant 16.0 si Microsoft utilisait toujours le schéma de numérotation qu’ils ont utilisé par le passé. Mais que se passe-t-il si, puisque vous supposez qu’ils vont spécifier une version 2013 ou 2016, vous avez du code à l’intérieur de la fonction qui recherche des dossiers avec ces versions ou autre chose ?

Voici un exemple où vous pourriez utiliser la chaîne $Version dans un chemin de fichier. Si quelqu’un passe une valeur qui ne complète pas un nom de dossier Office2013 ou Office2016, cela échouera ou fera quelque chose de pire, comme supprimer des dossiers inattendus ou modifier des éléments que vous n’avez pas pris en compte.

Assuming Parameter Values
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Version ) Get-ChildItem -Path "\\SRV1\Installers\Office$Version" } PS> Install-Office -Version '15.0' Get-ChildItem : Cannot find path '\SRV1\Installers\Office15.0' because it does not exist. At line:7 char:5 Get-ChildItem -Path "\\SRV1\Installers\Office$Version" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CategoryInfo : ObjectNotFound: (\SRV1\Installers\Office15.0:String) [Get-ChildItem], ItemNotFoundExcep tion FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Pour limiter l’utilisateur à ce que vous attendez qu’il entre, vous pouvez ajouter une validation des paramètres PowerShell.

Utilisation de l’attribut de validation des paramètres ValidateSet

Il existe différents types de validations de paramètres que vous pouvez utiliser. Pour une liste complète, exécutez Get-Help about_Functions_Advanced_Parameters. Dans cet exemple, l’attribut ValidateSet serait probablement le meilleur choix.

L’attribut de validation ValidateSet vous permet de spécifier une liste de valeurs autorisées en tant que valeur du paramètre. Étant donné que nous ne prenons en compte que les chaînes 2013 ou 2016, je souhaite m’assurer que l’utilisateur ne puisse spécifier que ces valeurs. Sinon, la fonction échouera immédiatement, en lui indiquant pourquoi.

Vous pouvez ajouter des attributs de validation des paramètres juste sous le mot-clé Parameter d’origine. Dans cet exemple, à l’intérieur des parenthèses de l’attribut du paramètre, vous avez un tableau d’éléments ; 2013 et 2016. Un attribut de validation des paramètres indique à PowerShell que seules les valeurs 2013 ou 2016 sont valides pour Version. Si vous essayez de passer autre chose que ce qui est dans l’ensemble, vous recevrez une erreur vous indiquant que vous avez un nombre spécifique d’options disponibles.

Using the ValidateSet parameter validation attribute
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateSet('2013','2016')] [string]$Version ) Get-ChildItem -Path "\\SRV1\Installers\Office$Version" } PS> Install-Office -Version 15.0 Install-Office : Cannot validate argument on parameter 'Version'. The argument "15.0" does not belong to the set "2013,2016" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again. At line:1 char:25 Install-Office -Version 15.0 ~~~~ CategoryInfo : InvalidData: (:) [Install-Office], ParameterBindingValidationException FullyQualifiedErrorId : ParameterArgumentValidationError,Install-Office

L’attribut ValidateSet est un attribut de validation courant à utiliser. Pour une description complète de toutes les façons dont les valeurs des paramètres peuvent être restreintes, consultez le sujet d’aide Functions_Advanced_Parameters en exécutant la commande Get-Help about_Functions_Advanced_Parameters.

Ensembles de paramètres

Disons que vous ne voulez utiliser que certains paramètres PowerShell avec d’autres paramètres. Peut-être avez-vous ajouté un paramètre Path à la fonction Install-Office. Ce chemin installera la version de l’installateur. Dans ce cas, vous ne voulez pas que l’utilisateur utilise le paramètre Version.

Vous avez besoin d’ensembles de paramètres.

Les paramètres peuvent être regroupés dans des ensembles qui ne peuvent être utilisés qu’avec d’autres paramètres du même ensemble. En utilisant la fonction ci-dessous, vous pouvez maintenant utiliser à la fois le paramètre Version et le paramètre Path pour obtenir le chemin de l’installateur.

function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(Mandatory)]
        [string]$Path
    )
    
    if ($Version) {
        Get-ChildItem -Path "\\SRV1\Installers\Office$Version"
    } elseif ($Path) {
        Get-ChildItem -Path $Path
    }
}

Cela pose cependant un problème, car l’utilisateur pourrait utiliser les deux paramètres. De plus, puisque les deux paramètres sont obligatoires, ils seront obligés d’utiliser les deux alors que ce n’est pas ce que vous voulez. Pour résoudre ce problème, nous pouvons placer chaque paramètre dans un ensemble de paramètres comme ci-dessous.

function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'ByVersion')]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(Mandatory, ParameterSetName = 'ByPath')]
        [string]$Path
    )
    
    if ($Version) {
        Get-ChildItem -Path "\\SRV1\Installers\Office$Version"
    } elseif ($Path) {
        Get-ChildItem -Path $Path
    }
}

En définissant un nom d’ensemble de paramètres sur chaque paramètre, cela vous permet de regrouper des paramètres ensemble.

L’ensemble de paramètres par défaut

Que se passe-t-il si l’utilisateur essaie d’exécuter Install-Office sans paramètres ? Cela n’est pas pris en compte et vous verrez un message d’erreur convivial.

No parameter set

Pour résoudre ce problème, vous devrez définir un ensemble de paramètres par défaut dans la zone CmdletBinding(). Cela indique à la fonction de choisir un ensemble de paramètres à utiliser si aucun paramètre n’a été explicitement utilisé. Pour cela, modifiez [CmdletBinding()] en [CmdletBinding(DefaultParameterSetName = 'ByVersion')]

Maintenant, chaque fois que vous exécutez Install-Office, il vous demandera le paramètre Version car il utilisera cet ensemble de paramètres.

Entrée de pipeline

Jusqu’à présent, dans les exemples, vous avez créé des fonctions avec un paramètre PowerShell qui ne peut être passé qu’en utilisant la syntaxe habituelle -NomParamètre Valeur. Mais, comme vous l’avez déjà appris, PowerShell dispose d’un pipeline intuitif qui vous permet de transmettre sans problème des objets d’une commande à une autre sans utiliser la syntaxe « habituelle ».

Lorsque vous utilisez le pipeline, vous « chaînez » les commandes avec le symbole de pipe |, ce qui permet à un utilisateur d’envoyer la sortie d’une commande comme Get-Service à Start-Service comme raccourci pour passer le paramètre Nom à Start-Service.

L’ancienne méthode utilisant une boucle

Dans la fonction personnalisée sur laquelle vous travaillez, vous installez Office et avez un paramètre Version. Disons que vous avez une liste de noms d’ordinateurs dans un fichier CSV, avec la version d’Office qui doit être installée sur chacun d’eux dans la deuxième ligne. Le fichier CSV ressemble à ceci:

ComputerName,Version
PC1,2016
PC2,2013
PC3,2016

Vous souhaitez installer la version d’Office qui se trouve à côté de chaque ordinateur sur cet ordinateur.

Tout d’abord, vous devrez ajouter un paramètre ComputerName à la fonction pour passer un nom d’ordinateur différent à chaque itération de la fonction. Ci-dessous, j’ai créé un pseudocode qui représente du code qui pourrait se trouver dans la fonction fictive et j’ai ajouté une instance Write-Host pour voir comment les variables se développent à l’intérieur de la fonction.

Adding the ComputerName parameter
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateSet('2013','2016')] [string]$Version, [Parameter()] [string]$ComputerName ) <# ## Se connecter à distance avec du code ici Invoke-Command -ComputerName $ComputerName -ScriptBlock { ## Faire des choses pour installer la version d'Office sur cet ordinateur Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version } #> Write-Host "I am installing Office version [$Version] on computer [$ComputerName]" }

Une fois que vous avez ajouté le paramètre ComputerName à la fonction, vous pouvez le faire en lisant le fichier CSV et en passant les valeurs du nom d’ordinateur et de la version à la fonction Install-Office.

$computers = Import-Csv -Path 'C:\ComputerOfficeVersions.csv'
foreach ($pc in $computers) {
    Install-Office -Version $_.Version -ComputerName $_.ComputerName
}

Construction de l’entrée du pipeline pour les paramètres

Cette méthode de lecture des lignes du CSV et d’utilisation d’une boucle pour passer les propriétés de chaque ligne à la fonction est la « vieille » façon de le faire. Dans cette section, vous voulez abandonner complètement la boucle foreach et utiliser plutôt le pipeline.

Tel quel, la fonction ne prend pas en charge le pipeline du tout. Il semblerait intuitif de supposer que vous pourriez passer chaque nom d’ordinateur et version à la fonction en utilisant le pipeline. Ci-dessous, nous lisons le CSV et le passons directement à Install-Office, mais cela ne fonctionne pas.

No function pipeline input defined
PS> Import-Csv -Path 'C:\ComputerOfficeVersions.csv' | Install-Office

Vous pouvez supposer tout ce que vous voulez, mais cela ne fonctionne pas pour autant. Nous sommes invités à saisir le paramètre Version alors que vous savez que Import-Csv l’envoie en tant que propriété d’objet. Pourquoi cela ne fonctionne-t-il pas ? Parce que vous n’avez pas encore ajouté de prise en charge de pipeline.

Il existe deux types d’entrées de pipeline dans une fonction PowerShell : ByValue (objet entier) et ByPropertyName (une seule propriété d’objet). Lequel pensez-vous être le meilleur moyen d’assembler la sortie de Import-Csv en entrée de Install-Office ?

Sans aucune refonte, vous pourriez utiliser la méthode ByPropertyName, puisque, après tout, Import-Csv renvoie déjà les propriétés Version et ComputerName car ce sont des colonnes du CSV.

Ajouter la prise en charge de pipeline à une fonction personnalisée est beaucoup plus simple que vous ne le pensez. Il suffit d’utiliser un attribut de paramètre représenté par l’un des deux mots-clés : ValueFromPipeline ou ValueFromPipelineByPropertyName.

Dans l’exemple, vous souhaitez lier les propriétés ComputerName et Version renvoyées par Import-Csv aux paramètres Version et ComputerName de Install-Office, vous utiliserez donc ValueFromPipelineByPropertyName.

Étant donné que nous souhaitons lier ces deux paramètres, vous ajouterez ce mot-clé aux deux paramètres comme indiqué ci-dessous, puis vous exécuterez à nouveau la fonction en utilisant le pipeline.

Adding Pipeline Support
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName)] [ValidateSet('2013','2016')] [string]$Version, [Parameter(ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string]$ComputerName ) <# ## Connectez-vous à distance avec du code ici Invoke-Command -ComputerName $ComputerName -ScriptBlock { ## Faites ce qu'il faut pour installer la version d'office sur cet ordinateur Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version } #> Write-Host "I am installing Office version [$Version] on computer [$ComputerName]" }

C’est bizarre. Il n’a été exécuté que pour la dernière ligne du CSV. Qu’est-ce qui se passe ? Il a simplement exécuté la fonction pour la dernière ligne parce que vous avez omis un concept qui n’est pas requis lors de la création de fonctions sans prise en charge du pipeline.

N’oubliez pas le bloc de processus !

Lorsque vous devez créer une fonction qui implique la prise en charge du pipeline, vous devez inclure (au minimum) un bloc « embarqué » à l’intérieur de votre fonction appelé process. Ce bloc de processus indique à PowerShell que lorsqu’il reçoit une entrée de pipeline, il exécute la fonction pour chaque itération. Par défaut, il n’exécutera que la dernière.

Techniquement, vous pouvez également ajouter d’autres blocs comme begin et end, mais les scripteurs ne les utilisent pas aussi souvent.

Pour indiquer à PowerShell d’exécuter cette fonction pour chaque objet entrant, j’ajouterai un bloc process qui inclut le code à l’intérieur de celui-ci.

Adding the process block
function Install-Office { [CmdletBinding()] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName)] [ValidateSet('2013','2016')] [string]$Version, [Parameter(ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string]$ComputerName ) process { <# ## Connectez-vous à distance avec du code ici Invoke-Command -ComputerName $ComputerName -ScriptBlock { ## Faites ce qu'il faut pour installer la version d'office sur cet ordinateur Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version } #> Write-Host "I am installing Office version [$Version] on computer [$ComputerName]" } }

Maintenant, vous pouvez voir que les propriétés Version et ComputerName de chaque objet retournées par Import-Csv ont été transmises à Install-Office et liées aux paramètres Version et ComputerName.

Ressources

Pour approfondir le fonctionnement des paramètres de fonction, consultez mon billet de blog sur les fonctions PowerShell.

I also encourage you to check my Pluralsight course entitled Building Advanced PowerShell Functions and Modules for an in-depth breakdown of everything there is to know about PowerShell functions, function parameters, and PowerShell modules.

Source:
https://adamtheautomator.com/powershell-parameter/