Introduction au développement PowerShell Partie I
Auteur : Eric Vernié, responsable technique en charge des relations développeurs
Document de référence
Révision 1.0
Téléchargement
Téléchargez les sources
Table des matières
Pré-requis
Introduction
Introduction au langage de script de Powershell
Consommer un composant .NET avec Powershell
Développer une extension à powershell (CmdLet)
Modification du profile pour installer les cmdlets
Utilisation d'une cmdlet pour construire et consommer un service Web à la volée
Conclusion
Ressources
Pré-requis
Avant d'aller plus loin, il est important que lecteur
- ait des notions de développement avec la plate-forme .NET.
- ait installé Windows PowerShell https://www.microsoft.com/windowsserver2003/technologies/management/powershell/download.mspx
- ait Visual Studio 2005 sous la main.
Une version express entièrement gratuite est disponible ici. https://www.microsoft.com/express/
Introduction
Windows Powershell™ est un nouvel environnement de ligne de commande Windows spécialement conçu pour les administrateurs système. Il comprend une invite interactive et un environnement de script qui peuvent être utilisés indépendamment l'un de l'autre ou ensemble. Dans cet article, nous allons nous intéresser principalement à la manière de "programmer ou d'étendre" Windows Powershell.
Pour ceux qui souhaitent s'initier aux commandes Windows Powershell, je ne peux que les encourager à télécharger la documentation ici : https://www.microsoft.com/downloads/details.aspx?FamilyId=B4720B00-9A66-430F-BD56-EC48BFCA154F&displaylang=en.
Pour bien comprendre la philosophie de Windows Powershell, il est important de connaitre deux principes fondamentaux.
- Les commandes ne sont pas basées sur du texte mais sur des objets (.NET en l'occurrence)
- Les commandes sont extensibles.
Pour assimiler ces deux principes, nous débuterons par une introduction au langage de script de Windows Powershell, puis nous explorerons des notions plus avancées, telles que la consommation d'objet .NET. Enfin nous terminerons par le développement d'une simple extension à Windows Powershell, connue sous le doux nom de Cmdlet et nous explorerons un exemple plus complexe de cmdlet qui construit et compile à la volée un Service Web.
Introduction au langage de script de Powershell
Lorsque vous démarrez Windows Powershell, vous vous retrouvez dans un environnement type mode console que l'on connait depuis des années avec les commandes batch du DOS.
On peut y taper nos commandes favorites comme la commande DIR.
La commande CD (change directory), RMDir, MD, Del, help, etc. Mais en faisant bien attention vous vous apercevrez de quelques différences notables.
En effet, si vous aviez l'habitude de la commande DIR /W pour afficher en colonne, plutôt qu'en liste, vous découvrirez que cette option ne fonctionne plus. Alors pourquoi ? Tout simplement parce que la commande DIR n'existe plus. En effet, la réelle commande pour afficher les fichiers est get-childitem et DIR n'est qu'un alias mappé sur cette dernière. Il en est de même pour toutes les autres commandes. Si vous souhaitez voir tous les alias utilisez la commande "get-alias" prévue à cet effet.
Toutes commandes Windows Powershell sera donc construit sous cette forme. Faire l'inventaire de toutes les commandes et leurs utilisations n'est pas le but de cet article, mais si vous débutez, la commande get-help est un bon point de départ.
Pour nos démonstrations de scripts, nous allons utiliser une commande fournie avec Windows Powershell, la commande, get-process, qui permet de lister les processus en cours.
Alors allons-y.
Dans Windows Powershell, tapez la ligne suivante :
PS> get-process
Vous devriez voir en colonne, la liste des processus en cours.
Il est possible d'afficher cette liste d'une manière différente en utilisant le caractère "pipe" ainsi que le format liste
PS> get-process | format-list
Vous pouvez également arrêter n'importe quel processus en combinant plusieurs commandes avec le caractère "pipe"
PS> get-process notepad | stop-process
Arrêtons-nous sur cette dernière commande et décortiquons là.
Comme je le disais en introduction, Powershell manipule des objets plutôt que du texte. La commande "Get-process notepad", retourne dans une variable intrinsèque à powershell un objet de type .NET, puis le caractère "pipe" dans notre commande, indique à Powershell de continuer et de passer le résultat de la 1er commande à la seconde commande. Tous les processus notepad en cours seront alors arrêtés.
Pour vérifier ce que j'avance vous pouvez affecter le résultat de la commande à votre propre variable, ainsi :
PS> $MaVariable=get-process notepad
Puis tapez :
PS> $MaVariable
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName -------
------ ----- ----- ----- ------ -- -----------
57 3 1376 9644 58 0,05 4068 notepad
57 3 1376 9648 58 0,06 3248 notepad
On remarquera que j'ai plusieurs instances de notepad en mémoire
Si je tape la commande suivante :
PS> $MaVariable.Gettype()
IsPublic IsSerial Name BaseType --------
-------- ---- -------- True
True Object[] System.Array
On s'aperçoit alors que Powershell a construit en mémoire un tableau d'objets (System.Array).
La caractéristique d'un tableau, c'est que l'on peut y faire référence par son index. Pour accéder au premier élément du tableau :
PS> $MaVariable[0] Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id
ProcessName ------- ------ ----- ----- ----- ------ -- -----
------ 57 3 1376 9648 58 0,06 3248 notepad
Je peux alors itérer sur le contenu du tableau avec le langage de script de Windows Powershell qui se rapproche du c#
PS> for($i=0; $i -lt $MaVariable.GetLength(0); $i++) {$MaVariable[$i]}
On y trouve l'instruction for traditionnelle, l'initialisation d'une variable $i de type System.Int32 et l'opérateur de comparaison "-lt" (inférieur)
$MaVariable étant un tableau de type System.Array, je peux alors avec la méthode getLength retrouver sa longueur, et le tour est joué.
Mais je pourrais également itérer de manière plus simple comme ceci :
PS> foreach ($proc in $mavariable) {$proc}
Comme tout est objet, je peux également avec Windows Powershell référencer chaque propriété de chaque objet grâce à l'opérateur "." (point) comme ceci :
PS> foreach ($proc in $mavariable) {$proc.ID}
Comme dans tout langage, il existe d'autres instructions dans sa syntaxe que je ne détaillerai pas ici, mais vous retrouverez bien évidement :
- des opérateurs arithmetiques (+, - , *, /, %)
- Des opérations sur les tableaux
- Des opérateurs d'affectations (=, +=, -=, *=, /=, %=)
- Des valeurs booléens
- Des commentaires (#)
- Des opérateurs de comparaisons (-eq, -ne, -gt, -ge, -lt, -le)
- Des instructions conditionnelles (if, while)
- Des séquences d'échappement
- Des fonctions, etc
Comme tout bon programmeur, vous souhaitez évidement éviter de retaper à chaque fois la même chose. Pour ce faire, il est possible avec Windows Powershell, de créer ces propres fonctions.
Tapez la commande suivante :
PS> notepad MesFonctions.ps1
Pour créer un fichier qui se nomme MesFonctions.ps1
Ajoutez-y le code suivant :
Function AfficherProcessus{ param($NomProcessus) $MaVariable=get-process $NomProcessus out-host -
inputObject $MaVariable}
Pour vérifier son contenu
PS> type MesFonctions.ps1
Ensuite il faut charger le fichier
PS> . .\MesFonctions.ps1
Puis exécuter la fonction
PS> AfficherProcessus Notepad
Notre fonction accepte des paramètres en entrée, mais on peut également grâce à l'instruction "return" sortir de sa portée.
Enfin on peut développer des filtres qui permettent une action simple exemple.
Ajoutez dans notre fichier MesFonctions.ps1 le code suivant :
filter Ralentir ($Tempo=100) { if ($DernierAffichage) { $Duree= ([DateTime]::Now - $DernierAffichage)
.TotalMilliseconds if ($Duree -le $Tempo) { Start-Sleep -MilliSeconds ($Tempo - $Duree) } }
$DernierAffichage= [DateTime]::Now $_}
Puis rechargez les fonctions
PS> . .\MesFonctions.ps1
Puis tapez la commande :
PS> get-process | ralentir
L'affichage des processus se fait plus lentement.
Si vous regardez bien le code du filtre, vous devez y voir plusieurs choses intéressantes :
- La variable spéciale $_ qui correspond à l'objet actif dans notre pipeline (tuyau) en l'occurrence la liste des processus
- La possibilité d'appeler des méthodes statiques comme [DateTime]::Now d'une classe .NET
C'est ce dernier point que nous allons illustrer dans le paragraphe suivant : Consommer un composant .NET avec powershell
Consommer un composant .NET avec Powershell
Comme vous avez pu le constater, Windows Powershell est un environnement de script puissant et ouvert. Basé sur la plate-forme .NET, il permet d'en tirer la quintessence, comme par exemple la possibilité d'exécutez des méthodes statiques de n'importe quelle librairie .NET.
Dans cette démo, ce que je vous propose, c'est d'aller encore plus loin et d'afficher nos processus dans une Windows Form plutôt que sur la console par défaut.
La première à chose à faire est donc de charger la librairie .NET qui contient les Windows Forms dans Windows PowerShell
PS> [reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
GAC Version Location --- ------- -------- True v2.0.50727
C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.For...
Une fois l'assemblage chargé, on peut alors créer un Windows Form en mémoire à l'aide de l'instruction new-object
PS> $MaForm=New-Object System.Windows.Forms.Form
La variable $MaForm est donc désormais une Windows Forms que l'on peut afficher
PS> $MaForm.ShowDialog()
On peut également lui donner un titre particulier
PS> $MaForm.Text="Liste des processus courants"
Ensuite nous allons ajouter à notre Windows Form un contrôle qui sera capable d'afficher la liste des processus. Par exemple une DataGrid
PS> $MaGrid=New-Object System.Windows.Forms.DataGridPS> $MaGrid.Dock=[System.Windows.Forms.DockStyle]::FillPS> $MaForm.Controls.Add($MaGrid)
La grille est ajoutée à la liste des contrôles de la Windows Form et a la particularité de prendre toute sa surface.
Pour vérifier si cela a fonctionné
PS> $MaForm.ShowDialog()
Ensuite, nous allons remplir un tableau avec la liste des processus comme suit :
PS> $MesProcessus=New-object System.Collections.ArrayListPS> $MesProcessus.AddRange($(get-process))
Le tableau $MesProcessus doit contenir la liste de nos processus, il suffit alors d'affecter ce tableau à la datagrid
PS> $MaGrid.DataSource=$MesProcessus
Ensuite on affiche le résultat et le tour est joué
PS> $MaForm.ShowDialog()
Comme vous pouvez le constater, Windows Powershell est un environnement puissant, qui peut sans trop d'effort (pour peu que l'on connaisse la plate-forme .NET quand même) être étendu à l'aide de simple script.
Néanmoins, il existe des cas ou le scripting n'est pas suffisant, et qu'il faille étendre d'une manière différente les commandes Powershell. Pour ce faire, Powershell propose la possibilité de développer ces propres commandes (cmdlet), c'est ce que nous allons aborder dans le prochaine chapitre.
Développer une extension à powershell (CmdLet)
Les environnements traditionnels proposent généralement des commandes sous forme de plusieurs programmes exécutables, qui manipulent les entrées sorties sous forme de texte. Chaque programme doit fournir ses propres paramètres, sa gestion d'affichage etc ... Par contraste, les commandes Windows Powershell, sont des instances de classes .NET qui dérivent d'une simple classe nommée cmdlet. La commande doit fournir et valider des paramètres en entrée, fournir des détails sur le type d'objet et son formatage et c'est tout. Windows Powershell fait le reste, il parse les paramètres, fait la liaison avec leurs valeurs, formate et affiche la sortie. Comme vous le verrez dans les lignes qui suivent, développer une une cmdlet est très simple.
Pour développer une cmdlet peut importe le langage, c'est à votre convenance mais il faut que se soit un langage qui cible la plate-forme .NET, dans notre exercice d'ailleurs, nous utiliserons les 3 langages majeures de Microsoft, Visual Basic 2005, C#, et C++/CLI.
- Dans Visual Studio 2005 créez un nouveau projet de type ClassLibrary.
- Ajoutez les références aux assemblages suivants :
- C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll
- System.Configuration.Install
- Incorporez les espaces de noms suivants
VB | C# | C++/CLi |
Imports System.ComponentModel Imports System.Management.Automation Imports System.Collections.Generic Imports System.Diagnostics Imports System.Text Imports System.Configuration.Install |
using System.ComponentModel; using System.Management.Automation; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Configuration.Install; |
using namespace System::ComponentModel; using namespace System::Management::Automation; using namespace System::Collections::Generic; using namespace System::Diagnostics; using namespace System::Text; using namespace System::Configuration::Install; |
4.Dérivez votre classe de la classe Cmdlet
VB | C# | C++/CLi |
<Cmdlet(VerbsCommon.Get, "TestVB")> _ Public Class TestCommande Inherits Cmdlet |
[Cmdlet(VerbsCommon.Get, "TestCS")] public class TestCommande : Cmdlet |
[Cmdlet(VerbsCommon::Get, "TestCPP")] public ref class TestCommande : public Cmdlet
|
Le nom d'une cmdlet consiste en un verbe qui désigne l'action que nous voulons faire et un nom qui indique l'élément. Par exemple "Get" pour le verbe "TestVB" pour le nom.
A noter que nous utilisons l'attribut CmdletAttribute pour identifier la classe comme une cmdlet. Il permet au runtime de Windows Powershell de l'appeler et del'identifier.
5.Surchargez la méthode ProcessRecord()et le tour est joué
VB | C# | C++/CLi |
Protected Overrides Sub ProcessRecord() WriteObject("Test d'une commande cmdlet développée en VB :" + _message) End Sub |
protected override void ProcessRecord() { WriteObject("Test d'une commande cmdlet développée en CSharp : " + _message); } |
protected : virtual void ProcessRecord() override { WriteObject("Test d'une commande cmdlet développée en CPP/CLI : " + _message); }
|
A ce stade votre cmdlet est terminée, vous pourriez compiler et l'exécuter cela fonctionnerait. Néanmoins pour être tout àfait complète, une cmdlet n'est réellement utile que si on peut lui passer des paramètres.
6.Ajout d'un paramètre à notre cmdlet
VB | C# | C++/CLi |
Private _message As String <Parameter(Position:=0)> _ Public Property Message() As String Get Return _message End Get Set(ByVal value As String) _message = value End Set End Property |
private String _message; [Parameter (Position = 0)] public String Message { get { return _message; } set { _message = value; } } |
private :String^ _message; public : [Parameter (Position = 0)] property String^ Message { String^ get() { return _message; } void set(String^ value) { _message = value; } } |
On déclare une donnée membre privée _message ainsi qu'une propriété nommée Message. On marque en suite la propriété avec l'attribut ParameterAttribut en lui donnant la position 0 par exemple. (Pour de plus amples informations sur les attributs d'un paramètre, reportez-vous au SDK disponible ici https://msdn2.microsoft.com/en-us/library/aa830112.aspx)
Enfin notre cmdlet à besoin d'être enregistrée comme une snapin. Pour ce faire nous allons lui ajouter une classe qui dérive de la classe PSSnapIn.
VB | C# | C++/CLi |
<RunInstaller(True)> _ Public Class TestCommandeVBPSSnapIn Inherits PSSnapIn Public Sub New() MyBase.New() End Sub
Public Overrides ReadOnly Property Name() As String Get Return "TestCommandeVBPSSnapIn" End Get End Property
Public Overrides ReadOnly Property Vendor() As String Get Return "Vendor" End Get End Property
Public Overrides ReadOnly Property VendorResource() As String Get
Return "TestCommandeVBPSSnapIn" End Get End Property
Public Overrides ReadOnly Property Description() As String
Get Return "Ceci est une commande Powershell développée en VB" End Get
End Property
Public Overrides ReadOnly Property DescriptionResource() As String Get Return "DescriptionRessource" End Get End Property
End Class |
[RunInstaller (true)] public class TestCommandeCSPSSnapIn : PSSnapIn { public TestCommandeCSPSSnapIn() : base() { } public override String Name { get { return "TestCommandeCSPSSnapIn"; } } public override String Vendor { get { return "Vendor"; } } public override String VendorResource { get { return "TestCommandeCSPSSnapIn"; } } public override String Description { get { return "Ceci est une commande Powershell développée en CSharp"; }
} public override string DescriptionResource { get { return "DescriptionRessource"; } } } |
[RunInstaller (true)] public ref class TestCommandeCPPPSSnapIn : PSSnapIn { public : property String^ Name { virtual String^ get() override { return "TestCommandeCPPPSSnapIn"; } } property String^ Vendor { virtual String^ get () override { return "Vendor"; } } property String^ VendorResource { virtual String ^ get() override { return "TestCommandeCPPPSSnapIn"; } } property String^ Description { virtual String^ get() override { return "Ceci est une commande Powershell développée en C++/CLI"; } } property String^ DescriptionResource { virtual String^ get() override { return "DescriptionRessource"; } }
};
|
Il important de marquer sa classe avec l'attribut RunInstallerAttribut, pour que l'utilitaire installutil retrouve la classe qui sera enregistrée en tant que snapin. Toutes les propriétés surchargées ne retournent que des chaines de caractères décrivant la cmdlet, vous y mettez ce que vous voulez.
Il est temps maintenant de tester notre cmdlet.
1. Nous allons l'enregistrer à l'aide de l'utilitaire installutil.exe
PS>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil.Exe
CHEMIN\TestCS.dllPS>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil.Exe
CHEMIN\TestVB.dllPS>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil.ExeCHEMIN\TestCPP.dll Microsoft (R) .NET Framework
Installation utility Version 2.0.50727.312Copyright (c) Microsoft Corporation. All rights reserved.Running a transacted installation. Beginning the Install phase of the installation.See the
contents of the log file for the C:\Perso\Articles\01 -Powershell Partie I\CPP\TestCPP\debug\TestCPP.dll assembly's progress.The file is located at C:\Perso\Articles\01 - Powershell
PartieI\CPP\TestCPP\debug\TestCPP.InstallLog.Installing assembly 'C:\Perso\Articles\01 - Powershell PartieI\CPP\TestCPP\debug\TestCPP.dll'.Affected parameters are: logtoconsole = assemblypath
=C:\Perso\Articles\01 - Powershell Partie I\CPP\TestCPP\debug\TestCPP.dll logfile = C:\Perso\Articles\01- Powershell Partie I\CPP\TestCPP\debug\TestCPP.InstallLog The Install phase completed
successfully, and the Commit phase is beginning.See the contents of the log file for the C:\Perso\Articles\01 -Powershell Partie I\CPP\TestCPP\debug\TestCPP.dll assembly's progress.The file is
located at C:\Perso\Articles\01 - Powershell PartieI\CPP\TestCPP\debug\TestCPP.InstallLog.Committing assembly 'C:\Perso\Articles\01 - Powershell PartieI\CPP\TestCPP\debug\TestCPP.dll'.Affected
parameters are: logtoconsole = assemblypath =C:\Perso\Articles\01 - Powershell Partie I\CPP\TestCPP\debug\TestCPP.dll logfile = C:\Perso\Articles\01- Powershell Partie
I\CPP\TestCPP\debug\TestCPP.InstallLog The Commit phase completed successfully. The transacted install has completed.
2.Ensuite nous allons ajouter le snapin
PS> add-pssnapin TestCommandeVBPSSnapInPS> add-pssnapin TestCommandeCSPSSnapIn PS> add-pssnapin TestCommandeCPPPSSnapIn
Pour vérifier les snapins enregistrés.
PS> get-pssnapin Name : TestCommandeCPPPSSnapInPSVersion : 1.0 Description : Ceci est une commande Powershell développée en C++/CLI
3.Enfin testons notre cmdlet
PS> get-testvb $(get-date) Test d'une commande cmdlet développée enVB :05/10/2007 14:51:40 PS> get-testcs $(get-date) Test
d'une commande cmdlet développée enCSharp : 05/10/2007 14:52:44 PS> get-testcpp $(get-date) Test d'une commande cmdlet
développée enCPP/CLI : 05/10/2007 14:53:16
Comme vous pouvez le voir ici, je passe la date courante à ma cmdlet. Vous aurez remarqué la notation $(get-date), qui indique à Windows PowerShell d'exécuter la commande get-date avant notre cmdlet et de mettre le résultat dans une variable. Si j'avais tapé à la place PS>get-testvb get-date, Windows PowerShell aurez traité get-date comme une chaine de caractères et non pas comme une commande.
A noter également que je n'ai pas précisé le nom du paramètre (grâce à sa position), mais une commande PS> get-testvb –message $(get-date) aurait été équivalente.
Néanmoins ,comme nous l'avons vu en début d'article, les commandes Windows Powershellpeuvent être utilisées au travers de pipeline (de tuyau), c'est-à-dire que nous pouvons passer sur une seule ligne de commande plusieurs commandes séparées parle caractère pipe (|) comme cette commande :
PS> get-process notepad | stop-process
Dansl'état actuel des choses notre cmdlet ne supporte pas le pipeline, car rienn'indique de lier un paramètre au pipeline de sortie. Pour ce faire, nous allons modifier légèrement notre cmdlet pour prendre en compte le pipeline en ajoutant à l'attribut Parameter, l'option ValueFromPipeLine.
VB | C# | C++/CLi |
<Parameter(Position:=0, _ ValueFromPipeline:=True)> _ |
[Parameter(Position = 0,ValueFromPipeline=true)] | [Parameter(Position = 0,ValueFromPipeline=true)] |
Avec cette attribut positionné, il est désormais possible d'exécuter notre cmdlet de la manière suivante.
PS> get-date | get-testvbPS> get-date | get-testcsPS> get-date |get-testcpp
La commande get-date sera exécutée, puis le résultat sera fourni à notre cmdlet.
Modification du profile pour installer les cmdlets
Avec l'utilitaire installutil.exe vous avez vu comment installer une cmdlet dans Windows Powershell. Néanmoins, à chaque fois que vous quitterez l'environnement, vous devrez relancer les commandes d'installation. Ce qui peut être fastidieux.
Pour éviter ça, Windows Powershell fourni la possibilité de modifier le profile de l'utilisateur. Procédez comme suit.
1. Vérifiez que le fichier profil n'existe pas déjà :
PS> test-path $profile
Si la commande vous retourne Faux, vous devez en créez en.
2. Création du fichier de profile par défaut
a.Dans le répertoire documents de l'utilisateur, créez le répertoire WindowsPowershell
b.Créez le fichier Microsoft.PowerShell.Profile.ps1
PS> cd $Home\documentsPS> md WindowsProwerShellPS> NOTEPAD Microsoft.PowerShell.Profile.ps1
3. Ajoutez dans ce fichier la fonction suivante :
function pro { notepad $profile }
Elle aura pour but de charger le profile automatiquement lorsque vous taperez la commande pro
4.Ajoutez-y les commandes suivantes:
set-alias installutil C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil.Exe
installutil CHEMIN\TestVB.dll
add-pssnapin TestCommandeVBPSSnapIn
installutil CHEMIN\TestCS.dll"
add-pssnapin TestCommandeCSPSSnapIn
installutil CHEMIN \TestCPP.dll
add-pssnapin TestCommandeCPPPSSnapIn
Ou CHEMIN représente le chemin d'accès à la cmdlet
Désormais, à chaque fois que vous chargerez l'environnement Windows Powershell, l'installation de la cmdlet se lancera.
Utilisation d'une cmdlet pour construire et consommer un service Web à la volée
Comme nous venons de le voir, développer une cmdlet reste somme toute assez facile, si vous avez de bonne notion de développement avec la plate-forme .NET.
Dans l'exemple que je vous propose maintenant, c'est d'aller un peu plus loin et de pousser l'exercice en utilisant la puissance de Windows Powershell et de la plate-forme .NET, pour la création et la consommation d'un service Web à la volée.
Comme vous devez le savoir maintenant, un Service Web, est indépendant de la plate-forme et du langage utilisé. Cela permet à différent système de pouvoir dialoguer entre eux de manière transparente. Un Service Web, comme son nom l'indique, fonctionne essentiellement aujourd'hui au travers du protocole http (bien que l'on puisse utiliser d'autre protocole tel que TCPIP, SMTP etc..) et il doit fournir un service comme par exemple, un taux de change, la météo, le prix des bananes, j'en passe et des meilleurs.
Que diriez-vous alors de pouvoir à partir de Windows Powershell, exécuter n'importe quel bout de code à la volée qui se trouverait sur des systèmes distant et récupérer des données ? C'est ce que jeme propose de faire avec vous dans les lignes qui suivent.
Pour pouvoir accomplir cette tâche, il m'a fallu développer plusieurs composants que je ne détaillerais pas ici car cela serait hors sujet (vous trouverez de toute manière tout le code avec cet article).
Le projet est décomposé en 3 composants principaux.
- Le composant WSDLHelper, qui construit à la volée le proxy du service Web. Pour que notre démonstration fonctionne vous devez d'ailleurs vous assurez que vous possédez bien l'utilitaire "C:\ProgramFiles\Microsoft Visual Studio 8\SDK\v2.0\Bin\wsdl.exe
- Le composant CompilerHelper, qui compile à la volée le proxy créez par WSDLHelper
- La cmdlet PSServiceWeb, qui permet de lier tout ce beau monde et qui possède la commande get-ServiceWeb
Cette cmdlet possède plusieurs paramètres que je ne détaille pas ici, mais elle en possède un obligatoire URL qui est marqué avec l'option Mandatory=true et qui représente l'url du Service Web à utiliser.
Passons à la démonstration.
1.Installez la cmdlet
PS> installutil PSServiceWeb.dllPS> add-pssnapin CommandeServiceWebPSSnapInPS> set-alias wsdl
CommandeServiceWebPSSnapIn\get-ServiceWeb
2.Créez un répertoire c:\temp
3.Allez sur le site http://www.xmethods.net pour sélectionner un Service Web
4.Sur ce site allez tout en bas de la page et sélectionnez le service suivant :
A noter qu'il est développé sur une plate-forme Glue.
5.Pour construire un proxy, il nous faut un fichier WSDL. Cliquez sur CurrencyExchange Rate
et copiez la ligne "http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl"
6.Allez dans Windows PowerShell et tapez la ligne suivante
PS> $ASSEMBLY=wsdl -url http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl
7.Désormais dans la variable $ASSEMBLY nous avons en mémoire notre proxy au service Web CurrencyExchangeService
Nous devons alors récupérer ses classes pour pouvoir les instancier.
PS> $ASSEMBLY.GetTypes() IsPublic IsSerial Name BaseType -------- ------------
-------- True False CurrencyExchangeService
System.Web.Services.Protocols.SoapHttpClientProtocol True True getRateCompletedEventHandler System.MulticastDelegate
True False getRateCompletedEventArgs System.ComponentModel.AsyncCompletedEventArgs
8.La classe qui nous intéresse ici est CurrencyExchangeService. Instancions-la.
PS> $SW=new-object CurrencyExchangeService
9.Puis listons les méthodes quelle possède
PS> $SW | get-member -membertype method TypeName: CurrencyExchangeService Name MemberType Definition----
---------- ----------Abort Method System.Void Abort()add_Disposed
Method System.Void add_Disposed(EventHandlervalue)add_getRateCompleted Method System.Void
add_getRateCompleted(getRateCompletedEventHandlerva...BegingetRate Method System.IAsyncResult BegingetRate(Stringcountry1, String
country...CancelAsync Method System.Void CancelAsync(Object userState)CreateObjRef Method
System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)Discover Method System.Void Discover()Dispose
Method System.Void Dispose()EndgetRate Method System.Single
EndgetRate(IAsyncResultasyncResult)Equals Method System.Boolean Equals(Object obj)GetHashCode
Method System.Int32 GetHashCode()GetLifetimeService Method System.Object GetLifetimeService()getRate
Method System.Single getRate(String country1,String country2)
La méthode qui nous intéresse ici est getRate() qui prend deux chaînes de caractères en entrée symbolisant les monnaies à utiliser.
10.Exécutons notre service Web
PS> $SW.GetRate("EURO","USA")
Vous devez obtenir le taux de change entre l'euro et le dollar.
Il est possible que le temps de réponse ne soit pas instantané, n'oubliez pas que vous faite une requête au travers d'internet.
Remarque :
Par défaut, la cmdlet créée le proxy en csharp dans le répertoire c:\temp sous le nom
PowerShell.Proxy.ServiceWeb.dll, mais vous pouvez changer le langage ainsi que le chemin de la manière suivante:
PS> $ASSEMBLY=wsdl -url http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl -path
c:\MonProxy -language vbCette commande créera sur la racine le fichier MonProxy.dll en Visual Basic
Conclusion
Comme nous le venons de le voir, Windows Powershell est un environnement qui va simplifier la vie des administrateurs, mais en tant que développeurs, vous allez pouvoir y trouver également votre compte. En effet, si vous êtes plus enclin comme votre serviteur à utiliser des commandes batch pour certains travaux de tous les jours, vous allez pouvoir étendre l'environnement Windows Powershell à votre convenance.
Sachez néanmoins, qu'avec Windows Powershell, nous pouvons encore allez plus loin. En effet dans la seconde partie de notre article, nous aborderons des notions plus approfondie encore comme la gestion de son propre fournisseur Windows Powershell, la possibilité de développer son propre hôte de commande Powershell. L'exercice consistera à permettre à un administrateur de pouvoir exécuter des commandes Windows Powershell d'administration à partir d'Excel et d'utiliser la puissance d'Excel pour formater le résultat.
Ressources
Pour ceux qui ont fortement investi dans VBScript, je les encourage à allez voir le document suivant Converting VBScript Commands to Windows PowerShell Commands
Un bon point de départ pour débuter, est la communauté française qui vient de se créer autour de Windows Powershell : http://www.powershell-scripting.com/
Pour télécharger les différentes versions de Windows Powershell
https://www.microsoft.com/windowsserver2003/technologies/management/powershell/download.mspx
Software development kit
https://msdn2.microsoft.com/en-us/library/aa830112.aspx
Site officiel américain
https://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx
Téléchargement
Téléchargez les sources