Powershell pour les débutants (2ème partie)

I. Présentation

Pour faire suite à mon article sur l'initiation à "Powershell pour les nuls (1ère partie)", je vais maintenant vous parler de quelques capacités intéressantes offertes par Powershell.

A. Avant-propos

Avant de développer ce sujet, j’attire votre attention sur le fait que les scripts Powershell s’exécutent sous le contrôle d’une “stratégie d’exécution”. Cette dernière peut être définie dans le registre et/ou via une stratégie de groupe.

Note : Bien que cela puisse paraitre évident à certains, la stratégie d’exécution ne s’applique pas lors d’un “copier-coller” de tout ou partie d’un script dans une console Powershell.

Vous pouvez afficher la stratégie d’exécution active via la commande :

Get-ExecutionPolicy

Les principales valeurs renvoyées sont :

ModeDétails du mode
RestrictedAucune exécution de script n’est autorisée
RemoteSignedLes scripts locaux sont autorisés mais les distants doivent être signés.
AllSignedTous les scripts doivent être signés pour être exécutés
UnrestrictedTous les scripts peuvent être exécutés (aucune sécurité)

Notez qu’il est possible de stipuler ponctuellement, ou outrepasser la stratégie d’exécution, lors du lancement de l’interpréteur :

Powershell.exe –ExecutionPolicy bypass –file monscript.ps1

Attention, au même titre que les autres programmes et autres codes exécutables “typiquement téléchargés” sur Internet, les scripts Powershell peuvent être bloqués par un flux alternatif (ADS – Alternative Data Stream). Cela se traduit par un message d’erreur relatif à la stratégie d’exécution. Dans ce cas, vérifiez que les propriétés du script et cliquez sur le bouton “Débloquer” le cas échéant:

ps1-ads

J’ajouterais qu’il faudra vous méfier des systèmes 64 bits qui proposent 2 environnements distincts :

- 64 bits : %windir%\System32\WindowsPowerShell\v1.0\powershell.exe

- 32 bits : %windir%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe

Pour modifier la stratégie d’exécution, (afin d’autoriser les scripts locaux non signés) vous pouvez utiliser la commande suivante :

Set-ExecutionPolicy RemoteSigned

Cette action est à effectuer dans chaque environnement, à moins que vous utilisiez une stratégie de groupe, comme suit :

B. Édition de GPO (gpedit.msc)

"Configuration Ordinateur … Modèles d’administration … Composants Windows … Windows Powershell … Activer l’exécution des scripts"

ps1-execpolicy

Cette approche aura l’avantage de configurer les 2 environnements en même temps (et un ensemble de machines, sous réserve d’utiliser un GPO de domaine).

II. Le dot-sourcing

Après cette introduction, la 1ère chose que je voulais vous présenter, porte le nom quelque peu barbare, de “Dot Sourcing”. En fait, il s’agit d’un concept très simple qui consiste à ajouter un point devant le nom du script à exécuter.

Attention, je ne parle pas du point qui stipule le chemin courant tel que “.\monscript.ps1” mais de cette syntaxe “. .\monscript.ps1”. (Un point, un espace, puis le chemin et nom du script).

Lorsque vous utilisez cette syntaxe dans la console (ou au sein d’un script), hormis le fait que le script s’exécute normalement, cela a pour effet de conserver les variables et les fonctions dans le contexte d’exécution. Autrement dit, c’est une sorte de commande “include”, permettant typiquement de charger des bibliothèques de fonctions contenues dans un fichier complémentaire.

Prenons un petit exemple pour illustrer :

Function Get-WMIServices
{
Get-WmiObject win32_service |
Select-Object State,Name,DisplayName,StartMode
}

$Result = Get-WMIServices

Echo "Script terminé."

Enregistrez ce code dans un fichier “Exemple.ps1”, puis exécutez-le dans une console Powershell.

.\exemple.ps1

Le message s’affiche mais une fois terminé, il ne reste aucune trace de ce script et de son contenu. Maintenant, exécutez-le de nouveau en ajoutant le “dot sourcing” comme suit :

. .\exemple.ps1

Le résultat semble identique, mais il n’en est rien. La fonction “Get-WMIServices“ est dorénavant “chargée” dans le contexte de la console. Vous pouvez invoquer cette fonction ou la variable “$Result” pour vous en assurer.

Cette technique peut être utilisée au sein d’un script (un peu comme si on importait des modules complémentaires) afin d’y inclure vos fonctions préférées, sans avoir à les dupliquer dans votre code principal.

Note : De nos jours, la technique d'usage du "dot-sourcing" a plutôt tendance à disparaitre au profit des modules, qui offrent une écriture généralement mieux structurée, voire spécialisée par famille thématique et plus pratique pour une réutilisation ultérieure.

Sur un plan plus technique, le dot sourcing permet d'exécuter le script dans la “portée courante". Autrement dit, les variables et les fonctions, qui auraient été "détruites" à la fin de l'exécution, deviennent réutilisables dans le contexte appelant.

Sous Powershell, la notion de portée, ou étendue ("scope" en anglais), est un concept qui détermine la "visibilité" des variables et des fonctions. Ce sujet peut rapidement devenir complexe et je me contenterais d'évoquer quelques rudiments :

Lorsqu'à partir d'une session Powershell, vous exécutez un script, ceci engendre un nouveau contexte d'exécution, (la fameuse portée) que l'on peut qualifier de "portée enfant", en référence à la "portée parente" qui correspond à la session à partir de laquelle elle a été créée. En quelque sorte, la portée enfant "hérite" des variables et des fonctions préalablement existantes dans son parent. Ainsi, ces dernières peuvent être lues et exploitées dans la portée enfant. En revanche, elles ne peuvent être modifiées que dans la portée où elles ont été créées. De la même manière, les portées parentes, ne peuvent aucunement lire, et encore moins modifier les variables ou les fonctions déclarées par leurs enfants.(Les portées sont implicitement "étanches").

Une petite illustration ?

Scope

En quelques mots, une variable ou fonction est déclarée implicitement en "local:" (règle par défaut) mais il est possible de stipuler la portée en cas de besoin, soit via l'option "-scope" des cmdlet, ou plus simplement en préfixant le nom via les libellés suivants :

Préfixe de portéeDescription
$global:varPermet d'accéder à la portée générale ou initiale. Typiquement celle générée lors du démarrage de la session Powershell.
$local:varImplicite. C'est la portée "actuelle" - crée lors de l'exécution d'une fonction, d'un script ou d'un bloc d'instructions. Visible dans les portées courante et enfants
$script:varPermet typiquement d'accéder à une variable du script à partir d'une fonction déclarée au sein même de celui-ci.
$private:varUsage de variables strictement réservées et visibles uniquement dans la portée actuelle (=non cessible ou pas d'héritage) - un peu comme par opposition à "public"
$using:varPermet typiquement de passer une variable "locale" à un script exécuté sur un ordinateur distant (Powershell v3 ou +)

Pour plus de détails sur les portées :

help about_scope

III. Les profils

A l’instar du “.profile” sous Unix, cette notion permet de définir des “préférences” à l’ouverture d’une session Powershell. En fait, il s’agit d’un ensemble de (4) scripts .ps1 exécutés au démarrage de l’interpréteur Powershell.exe. Mais auparavant, je vais simplement soulever quelques petits points de détail :

Les scripts de profil utilisent des noms et chemins spécifiques et sont exécutés (s’ils existent) dans l’ordre suivant :

Niveau machine (commun à tous les utilisateurs)

[1] - %windir%/system32/WindowsPowerShell/v1.0/profile.ps1
[2] - % windir %/system32/WindowsPowerShell/v1.0/Microsoft. WindowsPowerShell_profile.ps1

Niveau utilisateur (propre à chaque utilisateur)

[3] - %userprofile%/Mes documents/WindowsPowerShell/profile.ps1
[4] - %userprofile%/Mes documents/WindowsPowerShell/Microsoft. WindowsPowerShell_profile.ps1

Par défaut, il n’y a aucun script de profil existant. Toutefois, Windws 7/2008R2 propose un script “profile.ps1” (signé) fournit à titre d’exemple sous le dossier "%windir%\system32\WindowsPowerShell\v1.0\Examples\".

Sur un système 64 bits, pensez à adapter le dossier “System32” en “SysWOW64” si vous utilisez l’interpréteur 32 bits - Powershell (x86).

N’oubliez pas qu’un profil Powershell est avant tout un ”script”, et qu’il est donc soumis aux stratégies d’exécution.

Vous pourrez constater que par défaut, la variable automatique $PROFILE référence le nom et chemin complet du script de profil de l’utilisateur en cours. Toutefois, le fichier référencé n’existe pas (ni le dossier parent). Pour créer rapidement votre propre profil, il suffit de tapez la commande suivante :

new-item -path $PROFILE -type file -force

L’option “-force” permet de créer le répertoire parent s’il n’existe pas. Il vous suffira ensuite d’éditer son contenu, comme par exemple “notepad $PROFILE” puis d’y ajouter vos commandes préférées. Notez que les scripts profils sont exécutés en mode “dot sourcing”. Les fonctions et variables qu’ils contiennent seront disponibles dans la session et les éventuels scripts que vous exécuterez à partir de cet environnement.

A. Exemple de script de profil :

Si vous manquez d’inspiration, voici un petit exemple de script de profil :

#-----------------------------------------------------------------------
# fonction alternative à l'applet "Get-Service" afin d'obtenir
# le type de démarrage (via WMI)
Function Get-WMIServices
{
Get-WmiObject win32_service | Select-Object State,Name,DisplayName,StartMode
}
#-----------------------------------------------------------------------
# fonction d'affichage graphique d'un message (basée sur l'objet COM)
function Popup
{
param (
$Message='Pas de message',
$Titre='Indiquez un titre',
$Secondes=0
)

$wshShell = New-Object -ComObject wscript.shell
$wshShell.popup($Message, $Secondes, $Titre)
}

#-----------------------------------------------------------------------
# fonction alternative à la commande "Whoami" (basée sur un objet .NET)
function Qui-SuisJe
{
[system.security.principal.windowsidentity]::getcurrent().Name
}

#-----------------------------------------------------------------------
# Change la couleur d'affichage des messages d'erreur ('red' par défaut)
$Host.PrivateData.ErrorForegroundColor='magenta'

#-----------------------------------------------------------------------
# Définition de mes alias favoris 🙂
New-Alias -Name Grep -Value Select-String
Set-Alias -Name Out-Clip -Value C:\Windows\System32\clip.exe

set-Location C:\Scripts

Popup -Message "Bonjour $env:USERNAME" -Titre "Accueil Powershell" -Secondes 3

Pour tester votre profil Powershell, fermez puis rouvrez la session, ou exécutez-le en “dot sourcing” via la commande :

. $PROFILE

IV. La gestion à distance

Pour plus d'information sur les différentes techniques de gestion à distance, dont le service WS-Management utilisé par Powershell, vous pouvez vous reporter à mon article Administration à distance sur ce sujet. Voir également l'article de Florian sur la configuration de WinRM pour les besoins de Powershell à distance.

A. Configuration

Pour configurer rapidement l’accès à distance, entrez les commandes suivantes sur le poste cible :

Enable-PSRemoting

Cette commande active l'accès à distance sur le poste via le protocole http. Ce mode de communication nécessite l'authentification Kerberos à des fins de sécurité par défaut et n'est donc pas autorisé en workgroup.

A des fins de tests uniquement, vous pouvez autoriser l’accès HTTP non sécurisé via la commande Powershell suivante (à réaliser sur les différentes machines concernées, pour l'authentification réciproque):

Set-Item wsman:localhost\client\trustedhosts -value *

Pour utiliser un identifiant différent de celui que vous avez utilisé dans votre session pour accéder à la machine distante, préparez la pièce d’identité (credential) comme suit :

$cred = Get-Credential DomainOuMachine\Compte

Puis entrez le mot de passe désiré :

get-credential

Bien, maintenant que vous avez tous les éléments, il ne vous reste plus qu'à choisir la méthode d'accès désirée….

B. Accès distant en mode session

Enter-PSSession –ComputerName NomMachineCible –Credential $cred

ou, si vous n’avez pas préparé les identifiants :

Enter-PSSession –ComputerName NomMachineCible –Credential $(Get-Credential)

C. En mode invocation ponctuelle

$command = { get-service }Invoke-Command –ComputerName NomMachineCible –ScriptBlock $command –Credential $(Get-Credential)

Notez qu’il est tout à fait possible d’envoyer des commandes (ou bloc de code) à plusieurs ordinateurs simultanément:

Invoke-Command –ComputerName Server1,Server2,Server3 –ScriptBlock $command –Credential $(Get-Credential)

Vous pouvez également utiliser un simple fichier texte contenant la liste des machines à contacter :

Invoke-Command –ComputerName (Get-Content machines.txt) –ScriptBlock { get-service }

Vous pouvez également utiliser un script local (et d’éventuels paramètres) plutôt qu’un bloc de commandes trop complexes :

Invoke-Command –ComputerName (Get-Content machines.txt) –FilePath c:\scripts\exemple.ps1 –argumentlist Param1, Param2

Vous trouverez une quinzaine d’exemples dans l’aide en ligne ici

D. En mode Web

Depuis Windows Server 2012, Microsoft propose une fonctionnalité intéressante reposant sur la capacité d'administrer des machines à distance au travers un portail web dédié à Powershell. Cette passerelle dénommée "Powershell Web Access" présente un intérêt non négligeable pour ceux qui souhaitent accéder en mode commande à des machines à partir d'un simple navigateur Internet. Si cette fonctionnalité vous intéresse, reportez-vous vers l’excellent article de Florian sur le sujet : PowerShell Web Access.

Cette présentation est loin d’être exhaustive, mais elle constitue une introduction aux différentes techniques susceptibles de vous intéresser.

Bien à vous

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Christophe Mandin

Consultant/Formateur indépendant en quête de solutions et de moyens alliant efficacement la théorie et la pratique. Fort d’une expérience de plusieurs dizaines années dans l’informatique, j’ai pu apprécier de nombreuses problématiques, développer des qualités rédactionnelles et un esprit de synthèse, tout en me forgeant de solides fondamentaux théoriques, indispensables à toute analyse et mise en œuvre fonctionnelle. Malgré toutes ces années, je ne me lasse pas du plaisir de transmettre mes connaissances en misant sur 3 critères que sont les fondamentaux, la simplicité et le pragmatisme. Bien à vous. Retrouvez-moi sur Viadeo et LinkedIn : Christophe Mandin

    cnf1g a publié 32 articles sur IT-Connect.See all posts by cnf1g

    12 réactions sur “Powershell pour les débutants (2ème partie)

    • 19/12/2014 à 20:12
      Permalink

      >>le dot sourcing change la “portée” des variables et des fonctions, en les rendant “locales” au contexte.
      Non, le dot sourcing concerne l’exécution de code dans la portée courante et pas dans une nouvelle portée transitoire.

      #Transitoire
      $a

      #Portée courante
      .{$a=20;$a}
      $a

      Si un script contient la déclaration d’une variable globale : ($global:a=10)
      cela ne change pas sa portée. Elle ne peut donc être transformée en $local:a=10 comme le laisse penser ton explication.

      >>Vous trouverez une quinzaine d’exemples dans l’aide en ligne ici
      Il en manque un bout…

      Répondre
    • 20/12/2014 à 12:17
      Permalink

      Bjr
      1 – le dot sourcing change ( influence ?) la “portée” des variables et des fonctions, en les rendant “locales” au contexte (d’invocation ?) – C’est mieux ou pas ?
      2 – si la portée est stipulée explicitement dans la déclaration, elle n’est effectivement pas modifiable – désolé pour l’interprétation mais je ne voulais pas entrer dans le détail sur ce billet initiatique. Pour plus d’information cf–> help about_scopes ; help about_scripts | Select-String -Pattern « DOT SOURCING » -Context 1,10
      3 – Les exemples étaient ceux du technet, mais le lien a sauté lors de la rédaction…:-( mais comme je le stipulais ds le précédent billet, j’aurais du citer l’aide intégrée -> help Invoke-Command -Examples pour retrouver ces 15 exemples 🙂
      Cdt

      Répondre
    • 20/12/2014 à 12:31
      Permalink

      Précision : La mise en forme actuelle « mange » les antislashs mentionnés sur les chemins (cf profils et dot-sourcing) – On regarde pour un palliatif ou une correction …

      Répondre
    • 20/12/2014 à 22:58
      Permalink

      L’exemple précédent complet :
      $a=10
      #Transitoire
      $a

      #Portée courante
      .{$a=20;$a}
      $a

      >>C’est mieux ou pas ?
      Pour moi non, car tu parles des effets d’opérateurs d’appel (call operator) (help about_Operators) sur la portée (Scope) avant d’avoir abordée cette notion.

      Un de ces opérateurs d’exécution de code crée une nouvelle portée et n’utilise donc pas celle en cours, l’autre ne crée pas de nouvelle portée et utilise celle en cours.
      A partir de là, la déclaration d’une variable ou d’une fonction utilisera la portée en cours.

      Ici on change la portée, on précise dans quelle portée on crée quelque chose :
      New-Variable -Name ComputerName -Value ‘Localhost’ -Scope 1

      Là aussi, on précise dans quelle portée importer quelque chose :
      Import-Module MonModule -Global

      Ou encore :
      New-Item function:\Test { « code » } -Options private -Value

      Ce n’est pas du code de débutant, mais une fois que la notion de portée est acquise, plus besoin de revenir dessus. On peut progressivement assembler les concepts dans des instructions.

      Le concept de portée est un des points les plus important à comprendre sous Powershell.
      Mais de lui consacrer quelques lignes ne sera pas suffisant 😉

      >>mais je ne voulais pas entrer dans le détail sur ce billet initiatique.
      A mon avis, il s’agit ici d’un problème de structuration de ton tutoriel.

      De plus j’ai l’impression que tu n’as pas de relecteur, voir de relecteur technique (ce qui est encore mieux).

      Répondre
    • 23/12/2014 à 00:02
      Permalink

      J’ignore comment je dois prendre cette dernière allusion puisqu’il semble que tu assumes plutôt bien ce rôle 😉 mais en ce qui concerne les remarques, j’en prends bonne note et j’ai essayé de compléter l’article en ce sens, sans trop le charger.
      PS> Je n’ai pas la prétention d’être un maitre Jedi sur Powershell et encore moins être d’être « irréprochable » dans mes propos. Mais je fais de mon mieux, dans une démarche non mercantile, qui sera toujours perfectible. A mon avis, un article se doit d’être court et concis, et ces billets sont déjà bien longs, sinon il y a des bouquins ou des formations, pour compléter et aller plus loin …
      Que la force de Powershell soit avec toi … (pas trop quand même, car le coté obscur parfois ça pique un peu ;-))
      Cdt

      Répondre
    • 05/07/2016 à 11:12
      Permalink

      Bonjour,

      2 commentaires.

      Le premier :

      (un peu comme si on importerait des modules complémentaires)
      à changer en
      (un peu comme si on importait des modules complémentaires)

      Le deuxième :

      Un grand merci pour ces efforts de « vulgarisation » qui sont en train de m’aider (sinon de me former) au powershell. Ce contenu est précieux, à mon sens.

      Répondre
    • 05/07/2016 à 12:22
      Permalink

      Bonjour TyStef,

      À l’accoutumée, je mets un point d’honneur à soigner l’orthographe et la grammaire de mes articles, mais là j’avoue que je me suis « bien craqué » sur la concordance des temps.

      C’est corrigé.

      Merci pour ces remarques (les 2 🙂 )

      Au plaisir.

      Répondre
    • 11/11/2016 à 16:08
      Permalink

      Bonjour christophe,
      je sais pas si poster un message maintenant est convenable puisqu’il a été rédigé il y’a 2 ans. Mais bon.. le site est toujours bien référencé alors je vais tout de même donner un avis.

      Le cours est intéressant et relativement bien construit, mais si tu comptes nommer ton cours « Powershell, cours pour les débutants », je pense qu’il serait convenable de traiter les sujets de façon plus progressive.

      Par exemple le fait d’aborder le concept des scripts de profils ou d’accès à distance avant celui de boucles, fonctions,des cmdlets, etc., qui sont à mon sens plus fondamentaux, rend la lecture assez indigeste à qui n’a jamais vu de telles choses.
      Mais sinon bravo pour l’effort de vulgarisation.
      Bonne journée.

      Répondre
    • 14/11/2016 à 21:39
      Permalink

      Bonjour LittlePony,
      Je comprends (et respecte 🙂 ) l’argumentation mais je souligne qu’il ne s’agit pas d’un cours, mais plutôt d’une invitation à mettre le pied à l’étrier en matière d’usage de Powershell au quotidien. J’ai effectivement choisi un « découpage thématique et arbitraire » qui n’oblige en rien le lecteur à en respecter le séquencement. (Mea Culpa : J’aurais peut être dû le préciser 🙂 ) mais il fallait faire des choix.
      A mon avis, à l’instar du monde Libre, Powershell est avant tout un « shell » orienté administration ponctuelle et je considère le scripting comme une extension du langage… Tiens ça me rappele le dilemme de la poule et de l’oeuf, non 😀
      Mais comme disait A. Einstein « La connaissance s’acquiert par l’expérience, tout le reste n’est que de l’information. »
      Bonne continuation

      Répondre
    • 16/01/2017 à 11:29
      Permalink

      Bonjour Christophe,

      Un grand merci pour ton article qui se lit très facilement pour ceux qui font de l’administration système. Je suis surpris de la réaction de certains qui se fustige des termes employés dans ton article. Powershell est loin d’être en environnement inné et son vocabulaire peut vite devenir complexe si on veut être très rigoureux et du coup plus très compréhensible pour un débutant.
      D’ailleurs votre slogan s’adresse bien aux admins, non ? (‘Plate-forme de cours sur l’administration systèmes et réseau pour les professionnels de l’informatique’)
      Faire avancer les choses c’est top si cela est fait dans la bonne humeur, mais râler et critiquer, je trouve cela vraiment très bof pour du bénévolat.
      On arrive vite à dégoutter ceux qui prennent l’initiative d’aider !

      Bref, un grand merci à toi Christophe

      Répondre
    • 18/01/2017 à 09:21
      Permalink

      Bonjour Blacksheeps,
      Tout d’abord merci pour ces encouragements (Assurément, ils constituent le véritable « carburant des rédacteurs bénévoles »)
      Cela étant dit, la critique n’est pas toujours négative, pour peu qu’elle soit fondée et argumentée, elle fait avancer les sujets, (même si parfois, la forme est un peu lapidaire ou agressive.)
      Et comme disait mon défunt confrère, JCB, « la connaissance est le seul bien qui ne s’accroît que si on le partage » et j’ajouterais, « même si cela ne contente pas tout le monde, l’important n’est pas le nombre mais plutôt l’intention 🙂 )
      Bonne continuation à toi (et tous les lecteurs :-D)

      Répondre
    • 18/01/2017 à 11:49
      Permalink

      Christophe,
      Oh là la, je ne savais pas pour Jean Claude. 2 ans déjà 🙁 J’ai moi aussi été marqué par son investissement sans faille pendant des années sur Win95, NT 4.0, etc…et sa phrase magique que j’applique à la lettre du mieux que je peux.
      Il avait baissé le rythme sur les dernières années et ne mettait plus à jour son site web. Un grand salut à notre gourou de l’informatique.

      Philippe.

      Répondre

    Laisser un commentaire

    Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *