Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. PowerShell
  3. Fonctions avancées
Extrait - PowerShell Fonctionnalités avancées (2e édition)
Extraits du livre
PowerShell Fonctionnalités avancées (2e édition)
1 avis
Revenir à la page d'achat du livre

Fonctions avancées

Introduction

La fonction est un élément incontournable de la programmation. Il est important de maîtriser cette notion pour arriver à produire un code clair et évolué. Et c’est d’autant plus vrai que les fonctions avancées sous PowerShell proposent une multitude d’outils pour simplifier cette tâche. Toutefois, l’apprentissage peut s’avérer un peu ardu. Il est donc nécessaire de relire ce chapitre à plusieurs reprises, ainsi que de tester et retester les exemples qui y sont proposés.

Les fonctions avancées sont présentes depuis la version 2.0 de PowerShell. Elles reproduisent un fonctionnement comparable aux applets de commandes (cmdlet) natives PowerShell.

Aujourd’hui, la majeure partie des modules créés par la communauté exportent des fonctions avancées pouvant être utilisées comme des cmdlets natives.

Les atouts dont dispose une fonction avancée comparée à une fonction "basique" sont nombreux :

  • Implémentation des paramètres communs : -Debug, -Verbose, -WhatIf, -Confirm

  • Utilisation d’objets à travers le pipeline

  • Définition de plusieurs jeux de paramètres

  • Déclaration de paramètres dynamique

  • Implémentation d’une aide intégrée

  • Option et validation sur les paramètres...

Il est question...

Structure

Ce qui définit une fonction comme avancée est sa structure. En effet, des attributs sont à rajouter dans la structure pour que celle-ci devienne "avancée". On retrouve notamment l’attribut CmdletBinding().

Voici schématiquement ce que cela donne :

Function <Nom_de_la_fonction> { 
    [CmdletBinding()] 
    Param (<liste_des_paramètres>) 
    DynamicParam {...} 
    Begin {...} 
    Process {...} 
    End {...} 
} 

Il est également possible de rendre une fonction "avancée" en ajoutant l’attribut Parameter() sur l’un des paramètres, par exemple :

Function <Nom_de_la_fonction> { 
   Param 
     [parameter( mandatory = $true = 
   ) 
... 
} 

L’option mandatory rend un paramètre obligatoire ou optionnel. Une explication plus approfondie sera donnée plus loin dans le chapitre.

1. Param

Le bloc Param permet de définir l’ensemble des paramètres d’une fonction. Il est possible de définir les paramètres de deux manières :

#Première Méthode : 
Function <Nom_de_la_fonction> (<bloc_de_paramètres>) { 
... 
} 
#Seconde Méthode : 
Function <Nom_de_la_fonction> { 
    Param ( 
         <Bloc_de_paramètres> 
    ) 
    ... 
} 

Dans le cas d’une fonction avancée, seule la première méthode peut être utilisée. Il faut simplement renseigner le bloc Param, même vide, avec [CmdletBinding()].

Pour un paramètre, plusieurs éléments peuvent être indiqués :

  • un type,

  • une valeur par défaut,

  • l’attribut Parameter,

  • des attributs de validation.

Pour les deux premiers, la syntaxe est assez commune. Ici un exemple avec un paramètre de type chaîne de caractères ([string]) et ’localhost’ comme valeur par défaut :

Param...

Mise en situation

Dans cette section, les mises en situation présentées regroupent des syntaxes plus globales à la fonction, qui font intervenir différents éléments présentés précédemment, notamment la mise en place de jeux de paramètres, ou encore l’acceptation d’entrée par le pipeline.

1. Jeux de paramètres

Lors de la conception d’une fonction, il est intéressant de travailler sur des associations de paramètres. Pour chaque groupement de paramètres, la fonction a des actions différentes. Il s’agit là d’un fonctionnement courant dans les cmdlets natives de PowerShell.

Exemple avec Get-Process

PS > get-help get-process  
 
NOM  
   Get-Process 
 
RÉSUMÉ 
   Gets the processes that are running on the local computer or 
a remote computer. 
 
 
SYNTAXE 
   Get-Process [[-Name] <String[]>] [-ComputerName <String[]>] 
[-FileVersionInfo] [-Module] [<CommonParameters>] 
 
   Get-Process [-ComputerName <String[]>] [-FileVersionInfo] -Id 
<Int32[]> [-Module] [<CommonParameters>] 
 
   Get-Process [-ComputerName <String[]>] [-FileVersionInfo] 
-InputObject <Process[]> [-Module] [<CommonParameters>] 
 
   Get-Process -Id <Int32[]> -IncludeUserName [<CommonParameters>] 
 
   Get-Process [[-Name] <String[]>] -IncludeUserName 
[<CommonParameters>] 
 
   Get-Process -IncludeUserName -InputObject <Process[]> 
[<CommonParameters>] 

Un léger travail d’analyse est nécessaire. Les trois paramètres Id, Name et InputObject ne sont pas utilisables ensemble. Ensuite, IncludeUserName ne s’utilise pas avec l’ensemble ComputerName/Module/FileVersionInfo. Pour autant, les trois premiers paramètres s’utilisent bien chacun dans les deux ensembles de paramètres. C’est un cas élaboré de jeux de paramètres. Il est possible d’arriver à une telle complexité avec les fonctions avancées. Pour cela, il est nécessaire d’utiliser l’argument ParameterSetName...

Paramètre Dynamique

Il existe des cas d’usage où les options vues jusqu’ici ne répondent pas aux besoins. Prenons par exemple le cas d’un paramètre dont le contenu change en fonction de la valeur d’un autre paramètre, ou encore en fonction du provider (FileSystem, Registry, ActiveDirectory, etc.) dans lequel l’utilisateur se trouve.

C’est dans ces différentes situations que les paramètres dynamiques peuvent s’adapter et offrir des paramètres et/ou des valeurs changeantes en fonction du contexte.

1. Déclaration

La déclaration de paramètres dynamiques se fait au moyen de l’instruction DynamicParam{} à placer après le bloc Param() :

Param() 
DynamicParam{ 
  ... 
} 

Notons que la définition de DynamicParam{} se fait avec des accolades et non de parenthèses contrairement à Param(). En effet, il s’agit d’un bloc de script qui sera exécuté de manière régulière, afin de générer à la volée les paramètres dynamiques de la fonction.

Qui dit bloc de script, dit possibilité d’utiliser l’ensemble des fonctionnalités à disposition : commandes, fonctions, structure, comparaison, etc.

Toutefois, avant de présenter un exemple complexe, concentrons-nous sur le minimum nécessaire à la création d’un paramètre dynamique.

Toutes les commandes vues dans les parties suivantes sont bien entendu à placer dans le bloc de script de DynamicParam{...}. La partie En résumé offre une synthèse des trois parties qui la précèdent.

2. Nouvelle collection d’attributs

L’utilisation des attributs est expliquée à la section Param de ce chapitre. Dans cette dernière, il a été exposé qu’un paramètre peut avoir plusieurs attributs ([Parameter[]], [Alias()], etc.). Dans le cas des paramètres dynamiques, on utilise une collection d’attributs pour les regrouper. Celle-ci est créée avec la commande suivante :

    $attributeCollection = New-Object ` System.Collections.
ObjectModel.Collection[System.Attribute] 

Il s’agit ensuite de créer l’équivalent...

ArgumentCompleter et Dynamic ValidateSet

Les attributs ArgumentCompletions, ArgumentCompleter et Dynamic ValidateSet sont traités à part, car ils présentent quelques particularités. ArgumentCompletion a été ajouté avec la version 6.0 de PowerShell, et les deux autres ont une gestion dynamique de la validation ou de la complétion.

1. ArgumentCompletions

ArgumentCompletion s’apparente à ValidateSet, à la différence qu’il ne vérifie pas la valeur passée au paramètre. Les valeurs qu’on lui donne ne servent que de suggestions lors de l’autocomplétion via la touche [Tab].

La syntaxe reste similaire :

Exemple

Param (  
   [Parameter(Mandatory=$true)]  
   [ArgumentCompletions('Info','Warning','Error')]  
   [String]$Type  
) 

Ici l’utilisateur voit apparaître les suggestions Info, Warning et Error quand il utilise la touche [Tab] (autocomplétion) sur le paramètre -Type. Mais il peut tout à fait renseigner une autre valeur comme Information ou Alerte.

2. ArgumentCompleter

L’attribut ArgumentCompleter est plus complexe à prendre en main que les précédents attributs. En effet, celui-ci nécessite, comme ValidateScript, l’utilisation d’un bloc de script (scriptblock), à la différence que, contrairement à ce dernier, il doit retourner une ou plusieurs valeurs énumérées. Ces valeurs serviront de proposition à l’utilisateur lorsqu’il fera appel à l’autocomplétion, l’avantage étant qu’on peut prendre en compte une partie de la saisie utilisateur lorsqu’il fait appel à l’autocomplétion.

L’énumération d’objets concerne les éléments présents dans une collection/tableau. Ceux-ci sont renvoyés un à un dans la sortie, et non en un seul bloc. Dans le cas de ArgumentCompleter, il est nécessaire de respecter l’énumération au risque de se retrouver avec toutes les valeurs dès la première pression sur la touche [Tab].

Il est également possible d’utiliser une classe PowerShell à la place d’un bloc...

Register-ArgumentCompleter

La commande Register-ArgumentCompleter enregistre un compléteur d’argument (argument completer) personnalisé. L’idée est de faire la même chose que l’attribut ArgumentCompleter vu dans la section précédente.

La différence est que l’attribut se positionne sur un paramètre d’une fonction que l’on a écrite. La commande Register-ArgumentCompleter a un périmètre d’intervention plus vaste. Il est possible de positionner des Argument Completer sur des commandes PowerShell natives, comme Get-Service ou encore Get-Process. Il est également possible d’interagir sur des binaires comme ping.exe ou bien nslookup.exe.

Dans cette section, on va se concentrer essentiellement sur l’intégration sur des commandes PowerShell et non des exécutables.

Register-ArgumentCompleter permet également d’outrepasser l’autocomplétion déjà en place sur un paramètre. Par exemple, la commande Start-Service dispose d’une autocomplétion sur le paramètre -Name de l’ensemble des services présents sur la machine, sans distinction de leur état d’exécution. Pour se simplifier la tâche, il est possible d’enregistrer un Argument Completer qui proposerait seulement les services en état arrêté...

Splatting

Le splatting est une fonctionnalité disponible depuis PowerShell V2.0, mais recommandée en utilisation avec PowerShell V3.0. De quoi s’agit-il exactement ? Le premier avantage direct est la minimisation de la saisie des paramètres lors de l’utilisation d’une commande. En effet, certaines commandes ont un nombre assez important de paramètres obligatoires et cela peut rapidement devenir illisible, malgré l’utilisation du caractère ` ([Alt Gr]+7).

Exemple avec la commande Send-MailMessage

Send-MailMessage -Body 'Hello' ` 
    -From nicolas@akalya.fr ` 
    -SmtpServer mail.akalya.fr ` 
    -Subject 'Envoie par PowerShell' ` 
    -To stephane.vangulick@frpsug.fr ` 
    -Port 465 ` 
    -UseSsl 

Dans un autre cas, il n’est pas rare de devoir réutiliser une commande plusieurs fois avec les mêmes paramètres. D’ordinaire, on définit les paramètres un à un. Le bon réflexe est de centraliser les valeurs dans des variables, puis de les assigner aux paramètres de chaque commande.

Exemple

$ForegrounColor = 'Yellow' 
 
Write-host 'Hello' -ForegroundColor $ForegrounColor 
 
Write-Host 'World' -ForegroundColor $ForegrounColor...