Rien ne sert de courir, mieux vaut marcher dans la bonne direction

Une fois n’est pas coutume, j’ai décidé d’écrire mon premier billet de l’année à la date anniversaire de mon blog (qui fête ses 1 an) dans ma langue maternelle, la langue de Molière. En ce début d’année, c’est généralement la période des bonnes résolutions et l’objet double de ce billet est de vous expliquer pourquoi vous ne pourrez pas ignorer ou vous passez de Powershell en 2013 et quels sont les bons réflexes à acquérir pour découvrir et se simplifier la vie en Powershell.

Sans avoir besoin de sortir une boule de cristal, certaines tendances fortes montrent en quoi Powershell sera inévitable et indispensable en 2013:

  • L’ensemble des produits Microsoft est mis sur le marché en intégrant Powershell que ce soit directement au coeur de l’OS ou dans les applications de type ‘LoB (Line of Business)’. Ainsi, le client Windows 8 et sa version serveur Windows 2012 intègrent par défaut Powershell 3.0 et sont livrés avec un nombre impressionnant de cmdlets (se lit: “commande-let”). L’ensemble de produits Microsoft à destination des entreprises comme Active Directory, Exchange, SharePoint, Hyper-V et ceux de la gamme System Center, SCOM, VMM, Orchestrator, SCCM, viennent aussi avec un lot important de cmdlet permettant de maintenir et de piloter ces outils en Powershell. Il est même possible d’interagir avec le Cloud public en Powershell sur la plateforme Azure de Microsoft ou celle d’Amazon ou le cloud privé fournit par VMware. Cette nouvelle orientation semble être une nouvelle marque de fabrique des produits Microsoft auquel les autres éditeurs s’empressent d’emboiter le pas.
  • L’ensemble de la planète IT parlent d’automatisation, de ‘devops’ interprété comme le rapprochement entre les développeurs et les opérateurs du SI (admin système) ou comme une infrastructure sous forme de code (infrastructure as code). Que vient faire Powershell dans tout ça ? Eh bien c’est simple, c’est le ciment pour construire ces fondations et/ou ses relations que ce soit au sens propre ou figuré. C’est à la fois le langage utilisé au niveau du code pour atteindre le niveau d’automatisation nécessaire dans nos infrastructures et nos applications, mais aussi le langage commun sur le plan technique utilisé par les développeurs et les admins système et qui de ce fait facilite la communication entre ces deux mondes de moins en moins étanches qui ne peuvent plus se permettre de s’ignorer.
  • Concrètement, l’intérêt principal de Powershell est de gagner du temps lorsqu’il s’agit de répéter une opération ou une tâche qu’il s’agisse de la répéter dans le temps ou à grande échelle. Si je dois chercher la liste des utilisateurs dont le compte est verrouillé, je peux le faire manuellement la première fois en utilisant une console graphique (la mmc Active Directory) mais si je dois faire cela plusieurs fois par jour ou par semaine, cela devient vite fastidieux, répétitif et ennuyant. A la place, je peux tirer profit de PowerShell avec cette simple ligne de commande
    Search-ADAccount -LockedOut | Unlock-ADAccount

    ou en construisant un script qui va faire le travail à ma place. Idem, si je dois faire des modifications sur 3 comptes, comme changer leur date d’expiration, c’est plus facile et rapide de le faire dans une console graphique. Par contre si je dois modifier 2500 comptes, je vais utiliser Powershell pour exécuter cette tâche en boucle de telle sorte à éviter les erreurs et le côté fastidieux de la répétition.

  • Powershell c’est aussi vivant, derrière l’arbre se cache la forêt. PowerShell est aussi animé par une communauté de passionnés. Parfois, en plus d’être une passion, c’est même un art de vivre. Voici une liste non exhaustive où vous pourrez trouver de l’aide, des informations et entrer en contact avec la communauté Powershell et son remarquable travail: Twitter, Scripting Podcast, IRC chat, Powershell.org, Powershell Magazine, Scripting Games, Hey Scripting Guy, Script Gallery, Poshcode.org, des blogs, des flux RSS,…

Maintenant que le décor est planté, passons à la pratique. Vous pouvez évidemment suivre le conseil délivré par le titre de mon billet. Cependant, il peut s’avérer fort judicieux de se munir d’une carte et d’une boussole dans certains cas. Comme en sport, l’important c’est de participer. Aussi pour prendre un bon départ (mieux vaut tard que jamais), je vais à présent vous livrer le strict minimum vital à connaitre avant de se lancer dans l’aventure.

  • Tout est objet. Il ne faut jamais perdre de vue qu’en Powershell tout est objet. Cela signifie en d’autres termes, que chaque objet a des propriétés et des méthodes qu’il est possible d’appeler pour effectuer une action. Powershell étant riche, très régulièrement, seule une partie des propriétés sont présentées à l’affichage. Cela sera bien plus limpide lorsque vous lirez la suite…
  • Comme dans n’importe quel langage, lire l’aide est primordial. Tout étant objet, l’aide n’échappe pas à la règle. Bref il est plus que fortement recommandé d’appliquer et de mettre en pratique quasi religieusement le fameux adage ‘RTFM’ que l’on traduira ici en ‘Read the friendly manual’ pour rester à la fois politiquement correct et rester proche du sens du mot ‘fucking’ en anglais qui, sans être du Shakespear, ne sert parfois qu’à mettre l’emphase sur un mot ou une idée sans que cela soit nécessairement grossier. Pour chercher de l’aide ou même la parser, la parcourir, il suffit d’utiliser la commande Get-Help ou son alias man si vous venez du monde Unix (plus court à taper), suivi d’un mot clé. Cela permet de faire une recherche dans l’aide sur un mot clé. Si je tape Get-Help suivi du nom d’une cmdlet, j’obtiens la version courte associée à cette cmdlet. Au choix, je peux afficher toute l’aide en tapant Get-help [nom de la cmdlet] -Full ou je peux afficher l’aide dans un navigateur en utilisant le commutateur -Online comme argument.
    Les concepteurs ont aussi ajouté de la complétion qu’il est possible d’utiliser en tapant les premières lettres puis en utilisant la touche tabulation pour faire défiler les autres possibilités: Get-[touche Tab]
  • Tout étant objet en Powershell, il est possible de faire varier l’affichage et la présentation avec les cmdlets de mise en forme qui commencent toutes par le verbe Format- . Ces cmdlet de mise en forme servent également à découvrir les propriétés qui ne seraient pas affichées par défaut.
    Get-WmiObject -Class  Win32_OperatingSystem  
    # Pour faire apparaitre l'ensemble des autres propriétés, on fait:
    Gwmi Win32_OperatingSystem | format-list -Property *            
    Gwmi Win32_OperatingSystem |  fl  *

    # Plus fun, pour faire apparaitre des sous-propriétés d'un objet
    $host.UI | format-Custom -Depth 2
    $host.UI | fc -Depth 2            
    

  • Si je ne trouve pas ce que je recherche, c’est que la cmdlet est peut-être présente dans un module qui n’est pas (encore) chargé. En powershell version 3.0, les modules sont maintenant automatiquement préchargés. Même si cela nous facilite la vie, il reste néanmoins indispensable d’explorer la listes des commandes disponible dans un module. Dans ce cas, il y a 2 cmdlet à connaitre. Get-Command (abrégé en gcm ) et Get-Module qu’il est possible d’accompagner de nombreux commutateurs différents.
    Get-Module -ListAvailable

    gcm -Module PSDiagnostics

    gcm -Verb Get

  • Il convient aussi généralement de découvrir le type d’objet auquel nous avons affaire ou que nous souhaitons manipulé. Il peut s’agir des objets retournés par une cmdlet (l’output/la sortie) ou même du type d’objets qu’accepte une cmdlet, une fonction ou un paramètre. Cela peut sembler parfois plus facile à dire qu’à faire. Une cmdlet comme Get-Process va retourner une liste d’objet. Il y a une astuce qui nous permet d’interroger le vrai type de chaque objet appartement à cette liste. Pour ce faire, il suffit de transformer cette liste en tableau en entourant l’expression de @() puis de dire que nous voulons le premier élément de ce tableau en y acollant [0] ou le dernier avec [-1]. Voici un exemple concret qui va illustrer mon propos.
    # La cmdlet renvoie un tableau=array            
    @(Get-process).GetType()            
    # Le 1er élément du tableau est un objet process            
    @(Get-process)[0].GetType()            
    # Pour afficher le nom complet du type d'objet            
    @(Get-process)[-1].GetType().FullName


    Idem lorsque j’interroge l’aide, il y a 2 sections importantes sur le type d’objet accepté en entrée par une cmdlet, la section input, et le type d’objet retourné en sortie par la cmdlet, la section output. Dans l’exemple ci-dessus qui est l’aide associée à la cmdlet Get-Process, je peux aussi voir que le paramètre -Name accepte un tableau de chaines de caractères. Il est donc possible de faire:

    Get-process -Name notepad,iexplore

  • Venons-en aux méthodes. Pour les découvrir, la cmdlet Get-Member sera votre meilleur atout. Si je reprends mon exemple précédent, il semble pour le moins évident que je dois à présent interroger les méthodes associées à l’objet de type process. Pour ce faire, j’injecte simplement le résultat comme entrée à la cmdlet Get-Member qui est abrégée en gm. Concrètement cela donne:
    (Get-process)[0] | gm            
    (Get-process)[-1] | Get-Member -MemberType Methods


    Notez que la cmdlet nous affiche aussi le type d’objet auquel nous avons affaire, ce qui nous fait d’une pierre deux coups.

  • Toutes les cmdlets ne sont pas aussi inoffensives que celles dont le nom commence par le verbe Get-. Moins le verbe qui compose la cmdlet semble inoffensif, plus il est vivement conseillé d’utiliser le commutateur -Whatif qui permet de simuler ce qu’il va se passer. Avec la liste suivante, Restart- , Set-, Stop- , Clear- , Remove- , il semble assez évident que l’action réalisée par la cmdlet peut s’avérer dangereuse et effectuer des modifications indésirables.
    Restart-computer -Whatif

    Get-process -Name notepad | Stop-Process -WhatIf

  • Venons-en à l’un des concepts peut-être les plus difficiles à appréhender dans le langage PowerShell. Rien de tel qu’un peu d’humour pour marquer les esprits et retenir plus facilement ce qui se cache derrière cette clé de voute que représente le signe $_. Il n’y a pas si longtemps, le père du langage PowerShell a tweeté ceci:
    About $_
    Cela se traduit par: objet courant dans le tuyau (pipeline) comme variable à laquelle tu peux faire appel dans les expressions.
    C’est effectivement moins austère mais néanmoins proche de sa définition officielle dans l’aide qu’on obtient en tapant:

    get-help about_Automatic_Variables

    $_
    Same as $PSItem. Contains the current object in the pipeline object.
    You can use this variable in commands that perform an action on every
    object or on selected objects in a pipeline.

    C’est aussi l’occasion de comprendre ce qu’est ce tuyau, ce fameux pipeline. En gros, je peux imbriquer plusieurs cmdlet entre elles mais pour qu’elles s’emboitent correctement, il faut parfois faire des petites modifications sur le type d’objet. Commençons par un exemple simple. Disons que je souhaite obtenir la liste de tous les services qui tournent actuellement sur mon ordinateur. C’est aussi le premier exemple cité dans l’aide de la cmdlet Get-Service. Comme il n’existe pas de commutateur -Running ou de paramètre “-Status ‘Running'” qui me permettent de retourner uniquement les services qui sont lancés, je dois faire appel à la cmdlet Where-Object (abrégé en ‘?’) qui va me filtrer tout ça. J’envoie dans le tuyau (le pipeline) en entrée un tableau qui me liste l’ensemble des objets de type ServiceController. Pour faire appel à chaque objet unitaire envoyé dans ce tuyau, j’utilise ce fameux “$_” qui y fait référence. Je sais que l’objet serviceController a une propriété ‘Status’ et que celle-ci doit être égale à ‘Running’ lorsque le service est lancé. Bref, cela donne:

    Get-Service | Where {$_.Status -eq "Running"}            
    

    Depuis la version 3.0, dans des expressions simples, il est même possible d’omettre à la fois le fameux ‘$_’ et également les accolades (“curly braces”) qui marquent et délimitent une expression. L’expression suivante est donc équivalente:

    Get-Service | ? Status -EQ "Running"

    Prenons un second exemple, celui utilisé par Don Jones pour expliquer comment imbriquer des cmdlets. Son exemple est audacieux:

    Get-Service | Stop-Process -WhatIf

    Ceci va majoritairement échouer et vous allez obtenir beaucoup d’erreurs qui disent que le nom du service n’a pas été trouvé comme nom de processus. Si vous regardez attentivement, vous allez peut-être remarquer certains succès. Tentons de les isoler et de n’afficher que ceux-ci. Le code suivant permet de le faire:

    Get-Service | ? Status -EQ "Running" | ForEach {             
        If ($_.Name -in (Get-process).ProcessName) {            
            Stop-Process -Name $_.Name -WhatIf            
        }            
     }

    Dans chaque expression, le $_ fait référence à un objet de type servicecontroller issu de la toute première cmdlet Get-service. Avec une expression Si (‘If’), je vérifie juste que le nom du service existe dans la liste des noms de processus. Si c’est le cas, je tente l’arrêt avec la cmdlet Stop-Process. Le résultat en image:
    Encore une dernière précision un peu précoce mais à mettre dans un coin de sa tête pour plutard. Dans certaines constructions, il arrive que le ‘$_’ représente une autre objet, notamment dans un bloc de code ‘try {} catch {}’.

    Get-process | ? Name -EQ "notepad" | % {            
     try {            
      Stop-Process -Name $_.Name -ErrorAction Stop            
     } catch {            
      # Ici le $_ représente l'objet ErrorRecord            
      $_ | gm            
      $_             
     }            
    }


    Pour produire cette erreur, j’ai lancé notepad avec un ‘run as administrator’ et j’exécute le code ci-dessus dans un process powershell qui n’a pas été élevé, ce qui fait qu’il échoue naturellement avec un access denied.

Avec cette petite trousse de survie composée des outils ci-dessus, vous êtes à présent prêts à partir du bon pied dans la bonne direction. C’est maintenant votre tour de vous lancer dans l’aventure. N’oubliez pas qu’il faut se jeter à l’eau pour apprendre à nager et que vous nagerez d’autant mieux que vous pratiquez et vous vous exercez quotidiennement.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s