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

I. Présentation

Pour faire suite aux 2 premiers cours de cette série, je vous propose d’aborder les 2 autres sujets susceptibles d’améliorer votre progression. J’ai donc pensé à vous présenter quelques instructions ou mots clés du langage, la notion de fonction (juste quelques bases) et l’usage de l’éditeur graphique ISE.

Vous n'avez pas suivi les autres parties de ce cours sur PowerShell ? Pas de panique :

Avant de commencer, voici un petit tableau des principaux caractères spéciaux du langage Powershell. Vous devriez en connaitre déjà quelques-uns...

Symbole Nom Description
$ Dollar Préfixe le nom d'une variable ("$_" est l'objet en cours)
[ ] Crochets Encadre un type de variable ou l'indice des éléments d'un tableau [int] $var $tableau[$i]
{ } Accolades Encadre un ensemble de code  (bloc d'instructions expressions, filtres, boucles …)
( ) Parenthèses Groupe de commandes ou d'expressions (évite l'ambiguïté des évaluations)
| Pipe [AltGr]+[6] Pipeline (enchainement de commandes et/ou de filtres) – Peut être mis en fin d’une ligne de commande ds un script, la suite sur la ligne suivante.
. Point Membre d'une instance d’objet (méthode ou propriété)
(ou séparateur décimal, la virgule étant un séparateur de valeur)
, virgule séparateur de valeur, typiquement pour les éléments d’un tableau
.. Point Point Plage de valeurs (par exemple "1..10" désigne tous les chiffres de 1 à 10)
:: Double 2 points Membre statique d'une classe .NET
% Pourcent Reste de division (Modulo) Ou alias de la commande de boucle ForEach "%{$_}"
# Dièse Commentaire ou <# bloc de commentaire #>
` Anti-quotte ou Backtick [AltGr]+[7] - Caractère d'échappement (évite l'interprétation du caractère qui suit) – permet de couper une ligne d’instruction s’il est situé en fin de ligne
? Point d’interrogation Alias de la commande Where-Object
; Point virgule Permet d’écrire plusieurs instructions sur la même ligne. (ou de terminer explicitement une ligne d’instruction, et ainsi éviter une erreur d’interprétation lorsque le retour ligne est malencontreusement supprimé…)
@ Arrobase Tableau de valeurs si suivi de parenthèses @( ) ou table de hachage si suivi d’accolades @{ }
Cas particulier pour du “texte pur” @’  here-string ‘@
& Esperluette Opérateur d’invocation ou d'appel (Exécution d’un bloc de script ou d’une commande)
! Point d’exclamation Opérateur logique d’inversion équivalent à “-not”
Guillemets Encadre typiquement une chaine “non protégée”. Les variables $… sont remplacées par leur valeur respective ou rien si vide.
Simple quottes Encadre strictement une chaine en évitant toute interprétation des caractères qu’elle contient”.

Bien que déjà longue, cette liste n’est pas exhaustive, mais devrait largement suffire pour la suite de vos développements. On est bien dans une thématique d’initiation, non ?...

II. Quelques instructions

Dès lors que vous commencerez à écrire vos premiers scripts, il vous faudra connaitre quelques fondamentaux du langage. Je pense particulièrement aux instructions que sont les blocs de code et les boucles conditionnelles.

Donc pour faire court, voici quelques éléments de départ :

A. Les opérateurs

Je dirais que ces éléments sont pratiquement incontournables, surtout dès lors que vous coderez des directives de tests conditionnels. Ne confondez pas les opérateurs d’affectation “=” avec l’opérateur de comparaison “-eq” (ça arrive souvent, mais on se corrige très vite, puisque ça n’a rien à voir !)

Décrire tous les opérateurs serait long et fastidieux. Je vous présenterais donc les plus courants (quoi que cela dépende intimement des cas traités).

-eq : pour un test d’égalité “parfaite”. Ajoutez “–ceq” pour rendre l’opérateur sensible aux majuscules/minuscules.

-ne : pour un test de différence (n'est pas égal à)

-lt : pour un test d'infériorité stricte ou -le pour inclure l'égalité

-gt : pour un test de supériorité stricte ou -ge pour inclure l'égalité

-like : pour un test de concordance de contenu (correspondance avec un modèle) en associant le caractère de substitution “*” dans l’élément recherché. Cet opérateur ” fait partie de la famille des opérateurs de comparaison, au même titre que “-match”, “–notmatch”, “–notlike” sans oublier le très pratique opérateur d'évaluation de contenu "-contains" ou celui de substitution “-replace”.

-not ou ! : pour inverser une condition ou le résultat d’un test. Ne confondez pas les opérateurs logiques (booléens) avec les opérateurs au niveau du bit (-bAND, -bOR, -bXOR, -bNOT) plutôt assimilés à des opérateurs de comparaison.

Pour obtenir des informations sur les opérateurs en général, tapez :

Help About_Operators

Vous découvrirez les différentes familles d’opérateurs, telles que les opérateurs arithmétiques (+, -, *, /, %), d'affectation (=, +=, -=, *=, /=, %=), de comparaison (-eq, -ne, -gt, -lt, -le, -ge), logiques (-and, -or, -xor, -not, !), de redirection (>, >>, 2>, 2> et 2>&1), et bien d'autres encore.

Pour une aide détaillée sur chaque famille d’opérateurs, tapez une des commandes suivantes :

Help about_Arithmetic_Operators
Help about_Assignment_Operators
Help about_Comparison_Operators
Help about_Logical_Operators
Help about_Type_Operators
Help about_Split
Help about_Join
Help about_Redirection

Aparté : Vous pourrez rencontrer certains exemples comportant un opérateur particulier, dit de mise en forme "-f", permettant de formater une chaîne de caractères via les spécificateurs de format .NET. Son usage est particulièrement délicat et l'aide intégrée sur le sujet est plutôt pauvre. Voici donc une petite présentation de son potentiel :

Cet opérateur présente la particularité d’être précédé du motif/modèle de formatage qu’il utilise : Autrement dit, la syntaxe de base est la suivante :

"{<index>[,<align>][:<format>]}{<index>[,<align>][:<format>]}" –f valeur1, valeur2....

index : correspond au numéro d’ordre des éléments passés à l’opérateur -f (0 correspond à la valeur1 et 1 pour la valeur2 et ainsi de suite)

,align (caractère virgule puis valeur numérique) indique la position / décalage dans le "champ",  aligné à gauche si négatif , à droite si positif.

:format (caractère deux points puis caractère(s) MIN ou MAJ de format) – Quelques exemples de format :
o dn  : pour complète la valeur avec « n » zéros
o Xn : conversion de la valeur en hexa sur "n" caractères en majuscule
o P : conversion de la valeur en pourcentage
o C : conversion de la valeur en valeur monétaire
o hh : affiche uniquement l’heure d’une valeur "date"
o mm : affiche uniquement les minutes d’une valeur "date"

Chaque bloc de format est encadré par des accolades { } – les caractères entre chaque bloc de format tels que des espaces sont pris en compte. Le format des dates est très riche. Voici quelques exemples d'utilisation :

format Description Exemple Résultat
{0} Afficher uniquement les éléments désignés "{1}" -f "a","b" a
{0:X} Afficher un nombre entier au format hexadécimal majuscule "{0:X}" -f 255 FF
{0:x} Afficher un nombre entier au format hexadécimal minuscule "0x{0:x}" -f 255 0xff
{0:dn} Afficher un nombre décimal justifié à gauche complété avec des zéros "{0:d5}" -f 255 00255
{0:pn} Afficher un nombre en pourcentage (n= décimales ou arrondi) "{0:p}" -f 0.196"{0:p0}" -f 0.196 19.6 %20 %
{0:cn} Afficher un nombre en valeur monétaire (n= décimales ou arrondi : 2 par défaut) "{0:c}" -f 19 19.00 €
{0:hh} {0:mm} Afficher uniquement l’unité de temps d’une valeur de type date(hh=format 12h – HH=format 24h ) "{0:hh}:{0:mm}" -f (get-date) "{0:dddd}" -f (get-date) 10:32jeudi
{0,n} Afficher un champ de largeur "n" aligné à droite   (n étant positif) "[{0,7}]" -f "ab" [     ab]
{0,-n} Afficher un champ de largeur "n" aligné à gauche (n étant négatif) "[{0,-7}]" -f "ab" [ab     ]
{0,n:c} Afficher un nombre en valeur monétaire dans un champ de largeur "n" "[{0,8:C}]" -f 12.3 [ 12,30 €]

Les crochets servent uniquement à illustrer la notion d'alignement de ces exemples. Quelques informations complémentaires en anglais sont disponibles sur cette page du wiki TechNet.

B. Les blocs de code

Les blocs de code sont des ensembles ou “collections” d’instructions ou d’expression, couramment utilisées sous Powershell. Ils sont généralement délimités par des accolades { } mais sont souvent précédés d’une directive entre parenthèses (), comme par exemple :

Foreach ($item in $Collection) { Write-Host $Item.Name }

mais parfois cette structure peut être parfois chamboulée lors de déclaration de variables dynamiques comme par exemple :

$(get-service | where { $_.Name –eq “winrm” })

Pour des fonctions que nous aborderons ci-après, la syntaxe de base est plutôt du genre :

function edit-profil { notepad $PROFILE }

Les éventuels paramètres devraient être déclarés entre parenthèses après le nom de la fonction ou dans un bloc param () à l’intérieur des accolades de la fonction.

On retrouve également ces accolades pour l’invocation d’un bloc de script comme par exemple :

Invoke-Command -ScriptBlock { Get-WMIObject Win32_BIOS }

Vous l’aurez compris, la règle générale est difficile à établir, mais ce sont plutôt des accolades pour les blocs de script et des parenthèses pour les directives, et plus généralement pour forcer l’évaluation d’un résultat et en exploiter sa valeur de retour.

Sur un plan générique, si vous manquez d’informations sur les instructions et autres mots clés du langage Powershell, n’hésitez pas à consulter l’aide intégrée:

help about_Language_Keywords

III. Les instructions courantes

A. Les blocs conditionnels : if, elseif, else, switch

ps3-1

C’est probablement l’une des instructions les plus sollicitées, mais il n’y a aucune statistique là-dessus. Sa structure est la suivante :

if (test ou condition) { code à exécuter si la condition est remplie (soit vraie) }

Ce bloc de code peut être suivi (facultatif) par une directive “else” pour effectuer des actions dans le cas contraire, ou bien de “elseif” si un test alternatif est nécessaire. On parle alors de conditions imbriquées.

elseif (autre test ou condition) { code à exécuter si cette nouvelle condition est remplie (soit vraie) }
else { code à exécuter si aucune des conditions if, ou elseif n’est remplie (soient fausses) }

Obtenez plus d’informations via :

help about_if

ps3-2

L’imbrication de conditions multiples est parfois difficile à établir et vous pourrez alors recourir à la directive “switch” (similaire au “select case” en vbscript) permettant de tester plusieurs cas de figure. Sa structure est la suivante :

switch (test ou évaluation de valeur) {
valeur1 { code à exécuter si test est égal à valeur1;break }
valeur2 { code à exécuter si test est égal à valeur2;break }
valeur3 { code à exécuter si test est égal à valeur3;break }

default { code à exécuter si test est égal à aucune des autres valeurs }
}

Obtenez plus d’informations via :

help about_switch

B. Les boucles : for, foreach, do, while

Ces blocs de codes sont destinés à réaliser plusieurs itérations d’un même ensemble d’instructions. Ils ont toutefois besoin d’une directive stipulant les conditions de sortie, sous peine d’écrire une boucle sans fin :-).

ps3-3

La boucle “for” est une instruction relativement basique et rarement utilisée en raison de son caractère arbitraire. Sa structure est la suivante :

for ( valeur de départ ; test ou condition ; incrément / nombre d’itération }

par exemple, le code suivant affiche les chiffres de 1 à 5 :

for ($i=1; $i -le 5; $i++)
{Write-Host $i}

Obtenez plus d’informations via :

help about_for

ps3-4

Déjà évoquée dans les articles précédents, la boucle “foreach” est une instruction très fréquemment utilisée en langage Powershell. Contrairement à la directive “for”, cette instruction permet de parcourir un tableau ou une collection composée de 0 à n éléments, sans se préoccuper du nombre. Très proche, pour ne pas dire “similaire”, à l’applet de commande “foreach-object”, alias “%”, sa structure syntaxique est la suivante :

$Collection = 1..10
foreach ($item in $Collection) {
write-host $item
}

Obtenez plus d’informations via :

help about_foreach

ps3-5

La boucle “do” nécessite une condition de sortie définie dans la directive “while” ou “Until” (c’est à dire, “tant que la condition n’est pas” ou “jusqu’à ce que la condition soit” remplie ou vérifiée) – Il est également possible d’utiliser la directive “while” sans stipuler le “do”.

Structure d’une boucle “do” :

do {
  $valeur++
  Write-Host $valeur
} until | while ($valeur –ge | –le 10)

Il existe de nombreuses variantes d’écriture, selon que la condition soit traitée par “until” ou “while”, selon l’opération de comparaison et l’évaluation éventuellement inversée via un “not”… Bref, ce genre de code reste donc à la discrétion et préférence de l’auteur, l’essentiel, c’est que ça marche !…

ps3-6

A la différence de la directive suivante, les boucles “do” sont toujours exécuté au moins une fois. C’est à dire que la condition est évaluée après l'exécution du bloc de script. Dans le cas d’une boucle “while” uniquement, la condition est évaluée avant l'exécution du bloc de script.

Structure d’une boucle “while” seulement :

while($valeur -ne 10) {
  $valeur++
  Write-Host $valeur
}

Obtenez plus d’informations via :

help about_do
help about_while

IV. Les fonctions (Bases)

Voilà maintenant que les opérateurs et instructions de base ont été survolées, je vous propose d’aborder les fonctions sous Powershell. Là encore, c’est un vaste sujet pour lequel je vais essayer d’aller à l’essentiel.

ps3-7

Comme nous l’avons évoqué auparavant, les fonctions sont des blocs de script “nommés”, et utilisent la structure basique suivante :

function Nom { Code de la fonction }

Il s’agit là d’une fonction sans paramètre.

Note : A la différence de vbscript, Powershell ne fait aucune différence entre une fonction, plutôt destinée à renvoyer un résultat, d’une routine (“sub” en vbscript) chargée de réaliser des opérations. Pour faire simple, Powershell utilise un seul mot clé “function”.

Concernant le passage de paramètre à un fonction, vous disposez grossièrement de 2 écritures possibles :

via les parenthèses après le nom de la fonction, comme suit :

function dump-file ($Chemin, $Fichier) {
   get-content “$Chemin\$Fichier”
}

via un bloc param ( ) au début du code composant la fonction :

function dump-file {
param ($Chemin=$PWD,
$Fichier)
get-content “$Chemin\$Fichier”
}

Cette seconde écriture est plus élégante et à la préférence de nombreux développeurs, dès lors que la déclaration des paramètres devient complexe (typage, obligatoire, affectation, etc.)

Sans entrer dans les détails, vous constaterez que le nom des paramètres est directement exploitable. (via la complétion si la fonction est chargée). Si le nom des paramètres n’est pas précisé lors de l’appel de la fonction, c’est l’ordre de déclaration qui prévaut – Séparez les paramètres par un espace, ajoutez des guillemets ou simples quottes si la valeur comporte des espaces, et n’utilisez pas de parenthèses lors de l’invocation. ).

dump-file C:\Scripts Demo.txt
dump-file –Chemin C:\Scripts –Fichier Demo.txt

Voilà, j’avoue que c’est relativement succinct comme présentation, mais il faut bien un début …. (Je le complèterais peut-être dans un autre article dédié au sujet)

Notez qu’il est possible de quitter le contexte d’une fonction, ou bien d‘un bloc de script, en ajoutant la directive “return”, suivi d'une éventuelle valeur de retour et que pour quitter immédiatement une boucle (telle que Foreach, For, While, Do ou Switch), il faudra utiliser la directive “break”.

Avant de clôturer cette rubrique, j’ajouterais quelques mots sur des particularités que vous pourriez rencontrer sur des exemples glanés sur le net ou ailleurs...

Dans certains cas, une fonction peut être considérée comme un filtre. C’est à dire qu’elle doit traiter un ensemble d’éléments qui lui sont passés en paramètre, typiquement lors de l’usage dans un pipeline. Dans ce cas, et à défaut de le préciser, les instructions de la fonction sont traités pour chaque élément du pipeline, ce qui correspond à la directive “PROCESS { … }”. Toutefois, dans ce genre de traitement multiple, il peut être nécessaire d’effectuer quelques opérations spécifiques avant et/ou après le traitement individuel des éléments. (Un peu comme si vous vouliez constituer un tableau avec des titres/entêtes, afficher une ligne pour chaque élément entré, puis ajouter un pied de page).

Dans ce cas, vous pourriez utiliser une structure de la forme :

function Filtre {
begin { # code à exécuter au début, avant les traitement des éléments }
process { # code à exécuter sur chacun des éléments du pipeline }
end { # code à exécuter à la fin, après le traitement de tous les éléments }
}

Dans certains exemples, vous pourrez rencontrer le mot clé “filter”. En fait un filtre est un type de fonction qui s'exécute sur chaque objet du pipeline ($_). Un filtre ressemble à une fonction avec toutes ses instructions dans un bloc Process. La directive “filter” est en fait un “raccourci déclaratif” d’une "fonction filtre", comme par exemple :

filter Double {
$_ *2
}

Là encore, si vous avez un trou de mémoire, ou tout simplement besoin d’informations complémentaires :

help about_functions

Je ne doute pas de votre enthousiasme, ni de vos compétences mais je vous déconseille, si vous débutez bien-sûr, de consulter les autres rubriques “about_functions_advanced*” ou “about_functions_cmdletbinding” sans vous munir d’une bonne grosse boite d’antalgiques (paracétamol, doliprane, aspirine… faut en citer 3 je crois, non ?)

V. L’éditeur Powershell ISE

Si vous avez commencé à travailler sur Powershell, je doute que vous ayez suivi mes conseils à la lettre et que vous n’avez pas été tenté d’utiliser l’éditeur graphique, alias Powershell ISE (pour Integrated Scripting Environment).

Cette démarche est naturelle et légitime dès lors que le code contient un nombre de lignes conséquent, et la coloration syntaxique apporte un cachet de lisibilité évident.

Bien, donc avant d’entrer dans le vif du sujet, il me faut apporter quelques précisions :

Il existe de nombreux éditeurs de script Powershell fournis gratuitement, en évaluation ou payant chez plusieurs éditeurs tiers de logiciels (PowerGUI, PowerSE…). Par défaut, depuis Powershell v2, Microsoft propose donc un éditeur graphique (La v1 n’en proposait aucun) – Un raccourci est proposé par défaut sous Windows 7, mais il est en revanche nécessaire d’installer cette fonctionnalité sur Windows 2008R2. Une petite révision pour le faire en Powershell 🙂

Import-Module ServerManager
Get-WindowsFeature *ISE | Add-WindowsFeature –IncludeAllSubFeature

Et le tour est joué !… L’option “–IncludeAllSubFeature” permet d’activer le prérequis “.NET Framework 3.5.1” dans la foulée.

Note : Vous pourrez par la même occasion bénéficier de l'applet de commande "Out-Gridview", alias "ogv", citée dans un billet précédent.

Ce premier éditeur (v2) a de nombreux intérêts mais restait perfectible au vue de ces concurrents. La seconde mouture, fournie avec Powershell V3, est beaucoup plus aboutie, et propose de nombreuses évolutions, telles que la gestion des blocs de code (affichage/réduction des régions), l’intellisense (propositions dynamiques de complétion), des extraits prédéfinis (couramment appelés snippets), un module complémentaire d’assistance aux commandes, la coloration syntaxique également présente dans la fenêtre de sortie console, et pleins d’autres choses encore...

Mais je m’égare, puisque parler des bases consiste à traiter en premier lieu la première version de l’éditeur, donc la v2 (la suite en v3 ne sera qu’une formalité et du bonus…) – Comme pour la console vous disposez sur les systèmes 64 bits, de 2 déclinaisons 32 (x86) ou 64 bits. N’oubliez pas non plus l’élévation de privilège UAC en cas de besoin, ainsi que la stratégie d’exécution des scripts.

Powershell ISE v2 est donc composé par défaut, d’un menu et/ou d’un ruban d’icônes et d’une présentation répartie sur 3 volets ou zones, (qui peuvent être réorganisées via le menu “afficher” ou les icones à droite du ruban), comme suit :

ps3-8

Le volet de script en haut : C’est votre espace de travail pour l’écriture des lignes de code. Chaque script dispose d’un onglet dédié, affichant son nom (“sans-titre n.ps1” s’il s’agit d’un nouveau script). Notez que vous pouvez également ouvrir des scripts à distance (sous réserve d’avoir activé l’accès à distance et d’indiquer les bons identifiants de connexion).

Le volet de sortie au milieu : Les résultats de commande ou d’action sont retournés dans cette zone. Quelque peu déroutant, ce volet ne sera d’ailleurs plus proposé dans la version 3 et suivantes.

Le volet de commandes en bas : C’est la zone interactive qui vous permet d’entrer des commandes à l’instar de ce que vous feriez dans une console classique. Très pratique également lorsque vous êtes en mode “Debug”. Attention, il ne s’agit pas de la console au sens “$host”, mais d’une adaptation, souvent piégeuse. Si vous souhaitez utiliser la “vraie console Powershell”, utilisez le menu “Fichier … Démarrer Powershell.exe”, ou "[Ctrl]+[Maj]+[P]" ou bien encore cliquez sur l’icône ps3-9 du ruban.

L’un des avantages intéressants d’ISE est sa capacité à n’exécuter que la partie du code sélectionné. Pour cela, sélectionnez le code, puis utilisez le menu “Fichier … Exécuter la sélection”, ou cliquez simplement sur le bouton ps3-11 à droite du triangle vert d’exécution complète ps3-12 .

Vous remarquerez également, qu’avant chaque exécution de script, ISE vous proposera d’enregistrer le script. C’est une bonne pratique, qui peut vous éviter des désagréments en cas d’un méchant plantage inattendu :-(… Une étoile apparait à droite du nom du script (dans l’onglet) dès qu’il y a eu une modification non enregistrée.

Débogueur intégré :

Bien que ce sujet ne soit pas vraiment abordé dans une thématique “Découverte du langage”, notez que l’éditeur ISE dispose d’un débogueur intégré, relativement simple à implémenter (A mon avis beaucoup plus simple que le mode console :-D). Pour cela, il vous suffit de positionner des points d’arrêt via [F9] sur la ou les lignes où vous souhaitez que l’exécution s’arrête provisoirement. (Ces lignes, ou BreakPoints apparaitront sur fond rouge). Appuyez ensuite sur [F5] ou le triangle vert d’exécution afin que le code s’exécute jusqu’au prochain point d’arrêt. Utilisez ensuite le menu “Déboguer … Pas à pas …”, ou les touches [F10], [F11] ou [Maj]+[F11] selon le mode de progression désiré. N’hésitez pas à solliciter l’aide [F1] pour plus d’informations.

Au-delà de cette présentation succincte de cette interface graphique, au demeurant relativement simple à prendre en main, je voulais attirer votre attention sur une subtilité importante :

Les sorties d’affichage sont altérées : Par exemple, une applet de commande telle que “read-host” vous affichera un popup de saisie, de la même manière que “write-progress” affichera une barre graphique de progression. Ce n’est pas très important, mais gardez à l’esprit que ces arrangements peuvent altérer le comportement “naturel” du script. Prenez l’habitude de tester le rendu final via la console “native” (comme mentionné précédemment).

Un exemple concret me vient à l’esprit. Vous avez peut-être déjà éprouvé le besoin d’écrire une fonction “Pause” équivalente à ce que vous pouviez utiliser en mode batch. La solution pourrait alors ressembler à ceci :

# pour ceux qui ne se cassent pas la tête :-)
function Pause { cmd /c pause }

# pour les plus courageux :-)
function Pause {
  Write-Host "Appuyez sur une touche pour continuer..."
  $rk = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp")
}

Dans ces 2 exemples, la fonction Pause ne fonctionnera pas. Dans le premier cas, l’invite cmd ne sera pas visible, dans le second cas, on invoque l’objet console $host, qui n’existe pas vraiment dans le contexte de l’éditeur ISE.

Bien que cela n’ait pas d’intérêt absolu, mais au cas où vous auriez besoin de tester cet environnent d’exécution, (à l’instar de ce que certains scripts vbs faisaient pour distinguer les interpréteurs “cscript” et “wscript”), voici un petit exemple :

Function Pause ($Message = "Appuyez sur une touche pour continuer...") {
  if ((Test-Path variable:psISE) -and $psISE) {
    $Shell = New-Object -ComObject "WScript.Shell"
    $Button = $Shell.Popup("Cliquez sur OK ou appuyez sur [Entrée] pour continuer.", 0, "Script Paused", 0)
  }
  else {
    Write-Host -NoNewline $Message
    [System.Console]::ReadKey($true) | Out-Null
    Write-Host
  }
}

Ce script (ou fonction) teste la présence de la variable “$psISE” ainsi que l’objet associé (1 seul pourrait suffire, mais bon, l’exemple n’est pas de moi…) pour déterminer que le contexte est l’éditeur graphique. On en déduit que c’est la console qui est active dans le cas contraire.

En résumé, ISE a beaucoup d'atouts (surtout la v3), mais je regrette personnellement l'absence d'un champ ou menu destiné au passage de paramètre(s) à un script (cf PowerGUI). Pour ce besoin, vous devrez alors passer par la ligne de commande avant d'invoquer votre script...

Voilà, c’est tout (et je pense déjà beaucoup 😉 ) pour cette fois ci.

A la prochaine, et que la force de Powershell soit avec vous !

ps3-10

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 LinkedIn : Christophe Mandin

Nombre de posts de cet auteur : 32.Voir tous les posts

10 thoughts on “Powershell pour les débutants (3ème partie)

  • cet article manque d’exemples concrets comme pour les précédents

    Répondre
  • Il y a possibilité de stocker ses variables dans un fichiers à part?

    Répondre
    • Plutôt bizarre cette question, je ne voie pas bien le rapport avec cet article.
      Quoiqu’il en soit, sous Powershell, il y a trop de techniques autour du stockage d’information pour les citer.. Je propose donc un exemple simpliste :
      "Bonjour $Env:USERNAME" >> $Env:USERPROFILE\Desktop\FichierDemo.txt
      ou
      "Bonjour $Env:USERNAME" | Out-File "$Env:USERPROFILE\Desktop\FichierDemo.txt" -Append
      Voir aussi Set-Content, Add-Content, etc.
      Bonne continuation

      Répondre
  • Bonjour,
    Merci pour ce signalement,
    Pour ma part, je mentirais en disant que cette pratique ne m’affecte pas, ne serait-ce que par la perte de paternité de mes créations mais c’est malheureusement trop souvent la réalité du web et d’une certaine liberté déontologique qui en découle. Toutefois, ces copies manifestes de mes articles sur https://youracademy.fr/powershell/ commencent à dater mais au-delà de cette dérive, ces documents décrivent des fondamentaux qui restent toujours valables, surtout tant qu’ils demeurent gratuits et accessibles à tous.

    Le pire dans cette affaire, c’est que je ne suis même pas certain que ces copies soient fondamentalement malveillantes ou mercantiles mais plutôt issues ou « fuitées » d’une école (ISAM, GRETA…) ou bien encore d’un étudiant (BTS SIO) s’essayant au partage de ses notes et ressources, sans se préoccuper le moins du monde de la propriété intellectuelle des auteurs 🙁 .
    Je ne suis manifestement pas le seul auteur floué sur ce site, mais les propriétés des documents ne permettent pas d’identifier précisément l’origine et comme de domaine semble avoir été ouvert depuis plus d’un an, son contenu est désormais gravé dans les pierres du web.

    Cela n’entame pas ma volonté de partager et transmettre un savoir, même si je dois parfois pondérer mes informations et rester vigilant (Le prix de la gratuité, peut-être 😉 ) afin de préserver mon métier de formateur avec des supports actualisés et enrichis de l’expérience, au sein de mes prestations en présentiel ou à distance 😀 .

    Bien à vous

    Répondre
  • bonjour j essaye de faire un objet reprenant des valeur des differant commande

    $SRV = Get-ADComputer -Filter ‘operatingsystem -like « *Windows server* » -and enabled -eq « true »‘ -Properties * | Select-Object name,operatingsystem,IPv4Address
    $role = Get-WindowsFeature | Where-Object {$_.InstallState -eq « Installed »} | Select-Object name

    $SERVEUR = New-Object PSObject
    Add-Member -InputObject $SERVEUR -MemberType NoteProperty -Name Servername -Value $SRV.name -Force -PassThru
    Add-Member -InputObject $SERVEUR -MemberType NoteProperty -Name OS -Value $SRV.operatingsystem -Force -PassThru
    Add-Member -InputObject $SERVEUR -MemberType NoteProperty -Name IP -Value $SRV.IPv4Address -Force -PassThru
    Add-Member -InputObject $SERVEUR -MemberType NoteProperty -Name RandF -Value $role.name -Force -PassThru
    write-output $SERVEUR | ft

    le resultat :

    Servername
    ———-
    {AD-01, AD-02}
    {AD-01, AD-02}
    {AD-01, AD-02}
    {AD-01, AD-02}

    Servername OS IP RandF
    ———- — — —–
    {AD-01, AD-02} {Windows Server 2019 Datacenter, Windows Server 2019 Datacenter} {10.0.0.1, 10.0.0.2} {AD-Domain-Services, DHCP, DNS, FileAndStorage-Services…}

    c quoi c crochet? pige plus rien

    Répondre
    • Bonjour,
      A mon avis, il y a plusieurs erreurs 🙂
      Le résultat est affiché entre accolades car ce sont des ensembles (ou groupe) de propriétés des objets – Un peu comme la propriété « group » dans cet exemple simple
      Get-Command | Group Verb

      Ensuite, il faut « envoyer » l’interrogation des « roles » vers les machines à distance (ces infos ne sont pas dans les objets retournés via l’AD) et la commande « Get-WindowsFeature » marche à distance si le serveur est au moins sous 2012.

      La réponse dépasse le cadre de cet article pour débutant 😀 mais j’ai essayé d’extrapoler cette demande et la rendre compatible avec des serveurs 2008/PS v2

      # Adresse IP ou nom du DC
      $DC = '192.168.100.10'
      # Obtenir liste serveurs via AD
      $Cred = Get-Credential -Credential LABO\Admin
      $ADQuery = {
      Import-Module ActiveDirectory ; # PS v2 / Srv 2008
      Get-ADComputer -Filter 'operatingsystem -like "*Windows server*" -and enabled -eq "true"' -Properties * |
      Select-Object name,operatingsystem,IPv4Address }
      $Servers = Invoke-Command -ComputerName $DC -ScriptBlock $ADQuery -Credential $Cred

      # Interroger les roles sur chaque serveur (si ping OK)
      $Result = @()
      foreach ($Server in $Servers) {
      $Ping = Test-Connection $Server.Name -Count 1
      If ($Ping.Status -eq 'Success' -or $Ping.StatusCode -eq '0')
      {
      # Si serveur PS v2 / WS2008
      $GetRoles = {
      Import-Module ServerManager ;
      Get-WindowsFeature | Where-Object { $_.Installed } | select Name
      }

      $Roles = Invoke-Command -ComputerName '192.168.0.20' -ScriptBlock $GetRoles -Credential $Cred
      $Result += New-Object -TypeName PSObject -Property ([ordered]@{
      'Server' = $Server.Name
      'IPv4' = $Server.IPv4Address
      'OS' = $Server.operatingsystem
      'Roles' = $Roles.Name -join "`r`n"
      })
      }
      } # end foreach

      Write-Output $Result | Format-Table -Wrap

      Bonne continuation
      Christophe

      Répondre
  • Bonjour Christophe,

    Je vois très souvent le signe « % » utilisé avec des pipelines et/ou des accolades et manipulant parfois des objets autres que des chiffres ou des caractères, mais je ne vois pas vraiment ce que cela signifie, comment l’interpréter. Pourrais-tu en dire plus à ce sujet sur l’utilisation de ce signe % ?
    Exemple :

    $test | % {$boolvalue = $false}

    Répondre
    • Bonjour,
      A priori, la réponse a été trouvée 😀 et c’était aussi mentionné dans le tableau 😉
      Donc « % » est l’alias de « foreach-object » , pour le vérifier il suffit de taper « Get-Alias % »
      On peut toutefois mentionner une subtilité pour cette écriture plutôt adaptée au pipeline « % { $_ } » comparativement au mot clé « foreach » désignant une boucle comme par exemple « foreach ($item in $Collection) { $item } » plus adapté à un script. Mais le choix nous appartient.
      Bonne continuation

      Répondre

Répondre à Christophe Mandin Annuler la réponse

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

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.