PI Services

Le blog des collaborateurs de PI Services

Powershell 5.0 : Les classes

Introduction

Powershell 5.0 a bénéficié de plusieurs releases lors de l'année 2014, chacune d'entre elles apportant son lot de nouveautés/correctifs. Ce dernier est toujours en développement (la version finale n'arrivant qu'avec Windows 10) mais nous allons tout de même nous attarder dans cet article sur une nouvelle notion : la création de classes. Celle-ci n'était pas disponible nativement jusqu'en Powershell 5.0, ce qui pouvait paraître étrange pour un langage de scripting orienté objet. Je ferai un bref rappel sur les options disponibles avant cette version.

Dorénavant, nous pourrons créer nos propres objets personnalisés. Souvent, dans les scripts Powershell, on remarque l'utilisation de tableau ou de dictionnaire imbriqués et qu'il faut ensuite analyser pour récupérer la bonne valeur. Ces scripts obligent à avoir des algorithmes assez long et le script devient difficilement lisible en dehors du fait de ne pas être rigoureux. De plus, ils nécessitent souvent l'imbrication de multiples boucles de traitement influençant les performances générales du script.

Dans cet article, nous aborderons la création de classes d'objets en Powershell, l'ajout de propriétés et de méthodes ainsi que la façon d'instancier ("créer") nos objets. Pour certaines notions, une définition sera donnée (Cela permettra aux personnes non familières avec certaines notions de programmation objet de mieux appréhender le sujet).

Dans la suite de cet article, nous prendrons l'exemple d'une classe d'objet HRUser définissant un utilisateur dans le système RH pour illustrer la nouvelle syntaxe. Imaginons que cet exemple soit utilisé dans le cadre d'une interaction avec une base de données. L'objet utilisateur possédera les attributs suivant (nous ajouterons d'autres propriétés et des méthodes/fonctions ultérieurement) :

  • firstname
  • lastname
  • isCollaborator (un booléan permettant de savoir si l'utilisateur est un collaborateur)
  • salary (un nombre entier)

NB : Contrairement à la première beta, Powershell 5.0 est dorénavant disponible pour Windows 2012 et supérieur (qui n’était compatible qu’avec Windows 2012 R2 et supérieur). Le lien suivant vous mènera à la dernière beta sortie (Novembre 2014) :

http://www.microsoft.com/en-us/download/details.aspx?id=44987

Avant Powershell 5.0

Jusqu'à Powershell 4.0, il existait plusieurs méthodes pour créer des objets personnalisés en Powershell.

New-Object et NoteProperty :

La première méthode consiste à créer un objet de type PSCustomObject auquel on ajoute des propriétés de type NoteProperty.

Cependant, cette méthode ne permet pas d'ajouter des fonctions et le typage de nos attributs est dynamique. De plus, tout les objets personnalisés posséderont la même classe : PSCustomObject.

C# et Add-Type :

La seconde méthode était l'utilisation de code C#. Powershell pouvant interprété ce langage,  il est tout à fait possible d'écrire entièrement une classe en C# puis de l'ajouter dans une session Powershell via la commande Add-Type.

On peut ensuite créer l'objet grâce à la commande New-Object. Ce dernier possédera son propre type (HRUser) qui sera différent pour toutes les classes que vous créerez.

 

Il est aussi possible d'ajouter des fonctions statiques ou non à notre classe (nous reviendrons sur cette notion ultérieurement).

Cette méthode est complète mais nécessite de connaître le C#, ce qui complexifie aussi la lecture des scripts. Dans les prochains paragraphes, nous allons voir que Powershell offre dorénavant nativement les mêmes possibilités.

Les classes

Une classe contient la définition de nos objets ainsi que les traitements qui peuvent être effectués sur ceux-ci. Une nouveau mot clé apparaît dans Powershell 5.0 : “class” que l'on retrouve avant un scriptblock. Une classe se déclare de la façon ci-dessous :

Malheureusement, il n'existe pas encore de syntaxe pour gérer l'héritage de classe.

NB : Attention, les classes doivent obligatoirement être déclarées dans des scripts powershell. Une déclaration dans une invite de commande Powershell ne pourra donc pas être fonctionnelle.  De plus, lorsqu'une classe a été chargée, il est nécessaire d'ouvrir une nouvelle version avant d'en exécuter une version différente (elle ne peut pas être mis à jour dans une même session Powershell).

Les propriétés

Les propriétés contiennent tous les attributs de notre classe.

Celles-ci peuvent optionnellement contenir un type (comme dans l'exemple ci-dessus). Cela permet de réaliser de la validation sur les propriétés d'un objet.

Nous pouvons donc créer notre objet de type HRUser via la cmdlet New-Object en indiquant le type d'objet à créer.

 

On peut aussi créer un objet grâce à la méthode new qui existe dans chaque classe.

 

Toutes les propriétés sont initialisées avec une valeur par défaut (une chaîne vide, un booléen faux ou le chiffre 0 dans notre exemple).

On peut ensuite définir les propriétés de notre objet.

 

Attention, dans notre exemple, nos propriétés sont typées. On peut donc rencontrer une erreur si par exemple on définit une chaîne de caractères à la place d'un nombre pour la propriété “salary”.

ERROR PROPERTY TYPE

Les constructeurs

Un constructeur permet de créer un objet en initialisant certaines ou toutes de ces propriétés avec des valeurs fournies en paramètres et éventuellement d'effectuer des traitements lors de la création d'objets. La méthode “new” que nous avons vu précédemment correspond au constructeur par défaut. Mais il est possible d'en ajouter un ou plusieurs autre, c'est ce qu'on appelle la surcharge.

La syntaxe d'un constructeur est la suivante (il faut la placer à l'intérieur de la définition de notre classe) : On peut créer l'objet en lui passant des paramètres pour utiliser notre constructeur :

 

Ou

 

Cependant, on rencontrera une erreur si on ne renseigne pas tous les paramètres :

ERROR CONSTRUCTOR 

Pour palier à ce problème, on peut imaginer un second constructeur sans le salaire :

Les méthodes

Les méthodes sont l'équivalent de fonctions qui permettant d'interagir avec un objet. Nous allons créer une fonction permettant de gérer l'augmentation de salaire d'un employé.

Le type indiqué devant la méthode nous indique ce qui est retourné (“void” correspond à une méthode ne retournant rien).

Exemple d'exécution incluant une augmentation de salaire pour une personne :

EXEMPLE METHOD

Si nous souhaitons récupérer le nouveau salaire, il faut modifier la méthode en utilisant le mot clé “return” et en modifiant le type de retour.

Méthodes et propriétés statiques

Il reste un dernier mot clé à définir : “static”. Il permet de définir des méthodes et des propriétés qui sont accessibles sans avoir à créer un objet. Pour illustrer cette notion, nous allons ajouter une propriété représentant le total des utilisateurs du système. De plus, nous allons modifier les constructeurs pour incrémenter le compteur quand un utilisateur est créé.

On définit la propriété count :

 

On peut y accéder via : [HRUser]::count

Voici le script contenant l'intégralité de la définition de  la classe HRUser :

Exemple d'exécution :

EXEMPLE STATIC

Il aurait pu être intéressant d'intégrer la modification du compteur lors de la suppression de l'utilisateur dans la classe. Cependant, il n'existe pas de destructeur (méthode permettant de détruire un objet) dans la version actuelle de Powershell 5.0.

Conclusion

Nous avons aborder la création de classes d'objets en Powershell qui nécessite d'avoir des connaissances en programmation orientée objet. Initialement, Microsoft a ajouté cette notion pour simplifier la création de ressources pour Desired State Configuration (exemple : https://technet.microsoft.com/en-us/library/dn820211%28v=wps.640%29.aspx). A noter que lorsque vous charger une classe et que vous créer des objets, toutes les propriétés et méthodes associées sont accessible via l'auto complétion. Les classes écrites en Powershell sont une nouveauté et il reste encore des améliorations à réaliser :

  • l'héritage des classes.
  • la portée sur les propriétés : en Powershell, elles sont toutes publiques et donc accessible/modifiable depuis n'importe quel endroit dans un script. Changer la portée permettrait de spécifier des propriétés qui ne seraient accessibles que dans une méthode de la classe.