Vous êtes sur la page 1sur 70

Fonctions

1. Anatomie d’une fonction

En PowerShell et comme dans de nombreux langages, une fonction est un ensemble d’instructions auquel on donne 
un  nom.  Le  principal  intérêt  des  fonctions  est  que  l’on  peut  y  faire  référence  à  plusieurs  reprises,  sans  avoir  à 
ressaisir l’ensemble des instructions à chaque fois. Une fonction est constituée des éléments suivants : 

l un nom ; 

l un type de portée (facultatif) ; 

l un bloc param (facultatif) ; 

l un bloc d’instructions. 

En  ce  qui  concerne  le  type  de  portée,  nous  aborderons  cette  notion  un  peu  plus  loin  dans  ce  chapitre.  L’écriture 
d’une fonction nécessite la syntaxe suivante : 

Function [<portée> :] <nom de fonction>


{
param (<liste des paramètres>)
# bloc d’instructions
}

Prenons par exemple la fonction suivante : 

Function Bonjour
{
$date = Get-Date
Write-Host "Bonjour, nous sommes le $date" -Foreground Yellow
}

Cette fonction est la plus basique qui soit. À chaque appel, elle affiche un message en Jaune dans la console. Pour 
appeler une fonction, il suffit tout simplement de taper son nom : 
 

PS > Bonjour
Bonjour, nous sommes le 13/01/2018 13:18:54

2. Utilisation des arguments

Les arguments sont mentionnés ici par souci de complétude, mais sachez qu’il est largement préférable d’utiliser  les 


paramètres  (traités  dans  la  partie  suivante).  En  effet,  les  paramètres  représentent  le  moyen  de  choix  pour  passer 
des valeurs à des scripts ou fonctions, et ce depuis la version 2 de PowerShell. 

Une  notion  intéressante  dans  l’utilisation  de  fonctions  ou  de  scripts  est  le  passage  de  valeurs.  Pour  ce  faire,  une 
technique consiste à utiliser les arguments. Les arguments sont les valeurs placées derrière le nom de la fonction 
lorsque celle­ci est appelée. Voici la syntaxe de l’appel d’une fonction avec plusieurs arguments : 
<Nom de fonction> <Argument1> <Argument2> <ArgumentN>

Par exemple :  

PS > Bonjour Arnaud Robin

Dans cet exemple, Arnaud et Robin sont les deux arguments passés à la fonction Bonjour. 

Imaginons à présent que nous venions de créer une fonction qui affiche un message dans une boîte de dialogue. La 
question est, comment faire pour récupérer les arguments de façon à les insérer dans une boîte de dialogue ? Eh 
bien  la  réponse  est  toute  simple,  lorsque  nous  passons  des  arguments  à  une  fonction  (ou  à  un  script),  tous  se 
retrouvent  stockés  dans  un  tableau  d’arguments  appelé  $args.  Et  c’est  ce  tableau  que  nous  allons  réutiliser  à 
l’intérieur de la fonction (ou du script). $args[0] correspond au premier argument, $args[1] au second, etc. 

Prenons par exemple une fonction capable d’afficher une fenêtre pop­up comprenant un titre et un texte : 

Function Show-Popup
{
$WshShell = New-Object -ComObject wscript.Shell
$WshShell.Popup($args[0], 0, ’Popup PowerShell’)
}

Cette fonction fait appel à un objet COM du nom de wscript.shell. 

Lorsque nous ferons appel à cette fonction avec un ou plusieurs arguments, seul le premier sera pris en compte et 
affiché dans une boîte de dialogue : 

PS > Show-Popup "PowerShell c’est facile"

Notez  que  nous  avons  codé  le  titre  de  la  fenêtre  pop­up  « en  dur »,  mais  nous  aurions  pu  facilement  le  rendre 
paramétrable avec  $args[1]. Ceci dit, le principal problème de la technique des arguments avec $args est qu’on 
ne  sait  jamais  dans  quel  ordre  passer  les  valeurs  sur  la  ligne  de  commandes.  Tout  cela  est  grandement  amélioré 
avec la technique des paramètres, que nous allons voir tout de suite. 

3. Utilisation des paramètres
La  deuxième  façon  de  transmettre  des  variables  à  une  fonction  ou  à  un  script  est  d’utiliser  les  paramètres.  Nous 
vous recommandons vivement de privilégier les paramètres aux arguments. La syntaxe d’appel d’une fonction avec 
un paramètre est la suivante : 

<Nom de fonction> -<Paramètre> <Valeur du paramètre>

Ensuite, pour que PowerShell les interprète, il suffit de spécifier au début de la fonction ou du script les paramètres 
d’entrée grâce à l’instruction Param. 

Par exemple  

Function Show-Popup
{
Param([string]$message, [string]$titre)

$WshShell = New-Object -ComObject wscript.Shell


$WshShell.Popup($message, 0, $titre)
}

Avec ce principe, contrairement aux arguments, l’ordre n’a aucune importance à partir du moment où l’on spécifie le 
nom du paramètre. Cela signifie que les deux expressions suivantes donneront le même résultat : 

PS > Show-Popup -titre ’Mon titre’ -message ’Bonjour’

PS > Show-Popup -message ’Bonjour’ -titre ’Mon titre’

Si l’on ne souhaite pas préciser les noms des paramètres quand on appelle la fonction, alors il faudra tenir compte 
de  l’ordre  dans  lequel  ils  ont  été  déclarés  dans  le  bloc  param. En  effet  il  faut  s’assurer  que  les  valeurs  soient 
passées au bon paramètre. 

Ainsi nous pouvons appeler la fonction Show-Popup comme indiqué ci­dessous : 

PS > Show-Popup "Mon titre" "PowerShell c’est facile"

On peut également attribuer des valeurs par défaut aux paramètres comme si on initialisait une variable. 

Function Show-Popup
{
Param([string]$message=’Message...’, [string]$titre=’Titre’)

$WshShell = New-Object -ComObject wscript.Shell


$WshShell.Popup($message, 0, $titre)
}

Ainsi,  lors  d’un  appel  de  la  fonction,  si  les  valeurs  des  paramètres  Titre  et  Message  ne  sont  pas  renseignés, 
alors l’exécution se fera avec les valeurs définies par défaut dans le bloc Param. 
Exemple 

PS > Show-Popup

PowerShell  autorise  également  l’appel  de  fonctions,  scripts  ou  commandelettes  natives,  en  utilisant  une  partie  d’un 
nom de paramètre. On peut ainsi raccourcir les noms des paramètres autant que l’on veut dans la mesure où il n’y a 
pas d’ambiguïté entre plusieurs noms de paramètres. 

Par exemple  

PS > Show-Popup -t ’Mon titre’ -m "PowerShell c’est facile"

4. Retour de valeurs

a. Retourner une valeur scalaire

Une  fonction  peut  retourner  toutes  sortes  d’objets.  Pour  ce  faire,  il  suffit  d’insérer  l’objet  (ou  la  variable 
représentant  l’objet)  n’importe  où  dans  la  fonction  (ou  le  script)  pour  que  son  résultat soit  retourné.  Prenons 
l’exemple d’une fonction qui calcule la moyenne de deux nombres. 

Function moyenne
{
param ([double]$nombre1, [double]$nombre2)
($nombre1 + $nombre2) /2
}

Testons à présent notre fonction : 

PS > moyenne -nombre1 15 -nombre2 20


17,5

Le  résultat  ainsi  renvoyé  par  la  fonction  moyenne  est  un  objet  de  type  double,  et  non  pas  une  chaîne  de 
caractères ; gardez bien cela à l’esprit ! 

Bien  que  l’instruction  Return  existe  dans  PowerShell,  celle­ci  est  un  faux  ami.  Cette  instruction  laisse  à  penser 
que PowerShell ne retourne que ce qui est passé à cette instruction, ce qui est faux car PowerShell retourne toute 
valeur (ou tout objet) non affectée à une variable. Ce n’est donc pas une bonne pratique d’utiliser  Return (sauf dans 
les classes où c’est obligatoire). 

b. Retourner un objet

Le  retour  d’objets  par  un  script  ou  une  fonction  est  quelque  chose  de  nouveau  dans  un  Shell.  En  effet,  cette 
faculté était jusque­là généralement réservée aux langages de haut niveau tel que C# et consorts. Il va falloir s’y 
faire car il s’agit de l’essence même de la philosophie PowerShell. Et c’est aussi cela qui fait sa grande force ! 

Mais que se passe­t­il exactement lorsque nous exécutons les lignes de script suivantes ? 

Voyons ce qu’il se passe lorsque nous exécutons les lignes de script ci­après : 

# Récupère tous les processus en cours commençant par la lettre a


PS > $processes = Get-Process a*

# Arrête les processus récupérés précédemment


PS > Stop-Process $processes

Tout  simplement,  Get-Process  retourne  une  collection  d’objets  de  type  process  (tous  ceux  dont  le  nom 
commence par la lettre a). Cette collection est ensuite affectée dans la variable $processes. S’il existe plusieurs 
processus commençant par la lettre « a », alors le type de cette variable sera un tableau, sinon un scalaire. Enfin 
$processes est passée à la commande Stop-Process pour traitement et arrêt des processus contenus dans 
la collection. Vous l’aurez remarqué, à aucun moment il n’est question de récupérer des chaînes de caractères, ni 
de transmettre du texte. 

Si  vous  venez  de  VBScript,  il  va  falloir  vous  obliger  à  penser  différemment  car  vous  devrez  vous  empêcher  de 
retourner des  « données utiles » noyées dans une chaîne de caractères telle que  "La taille totale des
fichiers est de 15124 Ko.".  En  effet,  avec  un  tel  retour  il  sera  très  difficile  d’enchaîner  d’autres 
traitements. 

La  philosophie  de  PowerShell  est  de  renvoyer  soit  uniquement  la  valeur  15124,  soit  un  objet  possédant  une 
propriété nommée Taille ou Taille(Ko) contenant la valeur, tel que : 

Taille(Ko)
----------
15124

Ne  perdez  pas  de  vue  que  les  scripteurs  PowerShell  aiment  utiliser  le  pipeline  afin  d’enchaîner les  commandes 
dans le but de faire un maximum de choses, et ce en un minimum de lignes et d’efforts. 

Pour  arriver  à  ce  but  ultime,  vous  allez  devoir  vous  efforcer  à  renvoyer,  soit  des  objets  déjà  existants,  soit  vos 
propres objets. 

Dans l’exemple suivant, nous montrons ce qu’il ne faut pas faire : 

Function Get-FileInfo
{
Param([string]$Path)
$fichier = Get-Item $Path
"Nom : $($fichier.FullName)"
"Date de création : $($fichier.CreationTime)"
"Dernier accès : $($fichier.LastAccessTime)"
}

Bien  que  pas  vraiment  utile,  cette  fonction  à  but  éducatif  retourne  quelques  propriétés  choisies,  dont  voici  le 
résultat : 

PS > Get-FileInfo -Path .\Abonnés.txt

Nom : C:\temp\Abonnés.txt
Date de création : 01/13/2018 16:57:20
Dernier accès : 01/13/2018 16:57:20

Même si notre fonction remplit son office, elle renvoie du texte. Donc à part avoir un but informatif pour l’utilisateur 
final ou rediriger le résultat vers un fichier de log, elle ne permettra pas d’enchaîner un autre traitement. 

L’idée  est  donc  que  la  fonction  retourne  un  objet.  Ainsi,  il  sera  facile  d’extraire  les  valeurs de  ses  différentes 
propriétés. 

Voici donc le script final tel qu’il est préférable de l’écrire : 

Function Get-FileInfo
{
Param([string]$Path)
$fichier = Get-Item $Path
$fichier | Select-Object FullName, CreationTime, LastAccessTime
}

À présent, testons notre nouvelle fonction : 

PS > Get-FileInfo -Path .\Abonnés.txt

FullName CreationTime LastAccessTime


-------- ------------ --------------
C:\temp\Abonnés.txt 01/13/2018 16:57:20 01/13/2018 16:57:20

C’est  mieux,  n’est­ce  pas ?  Le  résultat  ressemble  enfin  à  ce  que  l’on  est  en  droit  d’attendre d’une  fonction 
PowerShell.  De  plus,  contrairement  à  la  version  de  départ  de  la  fonction,  nous  pouvons  à  présent  enchaîner  le 
traitement comme dans l’exemple ci­dessous : 

PS > Get-FileInfo -Path C:\temp\abonnés.txt | Reset-LastAccessTime

Bien  qu’il  soit  tentant  (et  possible)  de  vouloir  franciser  à  outrance,  tel  que  renvoyer  les  noms  des  propriétés  en 
français, nous vous recommandons de rester cohérent avec le nom des commandelettes qui sont en anglais. Cela 
permet d’éviter le « franglais » et donc de conserver une bonne homogénéité globale.  
5. Introduction aux « fonctions avancées »

Les termes « fonctions avancées » sont de nos jours devenus galvaudés car cette notion a fait son apparition avec 


PowerShell 2.0, ce qui remonte à quelques années... Ainsi, à l’heure actuelle, si l’on souhaite réaliser des scripts de 
qualité  professionnelle,  ces  fonctionnalités  dites  « avancées »  sont  devenues  le  minimum  syndical.  De  plus,  vous 
allez  vite  comprendre  qu’elles  vont  vous  simplifier  la  tâche  et  donc  que  leur  utilisation  est  tout  à  votre  avantage. 
Nous aurions donc tort de nous en priver !  

Pour  faire  court,  les  fonctions  avancées  permettent  de  réaliser  des  fonctions  qui  se  comportent  de  façon très 
similaire,  pour  ne  pas  dire  identique,  aux  commandelettes  PowerShell.  Cette  possibilité  permet  aux  scripteurs  de 
développer  aisément  de  nouvelles  commandes  en  PowerShell,  alors  qu’en  principe  le  développement  de 
commandelettes nécessite l’usage d’un langage .NET de haut niveau tel que C#. 

Une fonction avancée permet entre autres : 

l D’accepter des objets en entrée par l’intermédiaire du pipeline, 

l L’implémentation des paramètres communs : ­Verbose, ­WhatIf, ­ErrorAction, etc. 

l La validation des valeurs passées aux paramètres, 

l De rendre des paramètres obligatoires, 

l La création de plusieurs jeux de paramètres distincts, 

l La définition d’alias de paramètres, 

l … 

De plus, les fonctions avancées constituent la pierre angulaire dans la fabrication des modules PowerShell. En effet, 
pour des raisons de simplicité et de rapidité de développement, de très nombreuses commandes contenues dans 
les modules sont écrites en PowerShell sous forme de fonctions avancées. 

a. Différences entre les fonctions classiques et les fonctions avancées

On  distingue  facilement  les  fonctions  classiques  des  fonctions  avancées  car  ces  dernières  font  appel  à  l’attribut 
CmdletBinding. Cet attribut est riche en fonctionnalités mais nous n’en dirons pas plus pour le moment car il 
est presque secondaire par rapport aux autres fonctionnalités. Pour plus d’informations sur cet attribut, nous vous 
invitons à consulter la rubrique d’aide :about_Functions_CmdletBindingAttribute. 

Voici la syntaxe de la définition d’une fonction avancée dans sa forme la plus simple : 

Function <nom de fonction>


{
[CmdletBinding()]
Param (<déclaration des paramètres>)

Begin { # Bloc d’instructions optionnel utilisé qu’une fois }


Process { # Bloc d’instructions }
End { # Bloc d’instructions optionnel utilisé qu’une fois }
}

Comme  un  exemple  vaut  mieux  qu’un  long  discours,  voilà  à  quoi  ressemble  notre  précédente  fonction  Show-
Popup une fois transformée en fonction avancée. 
Function Show-Popup
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[ValidateLength(1,10)]
[String]$Titre,

[Parameter(Mandatory=$false)]
[String]$Message=’Message...’
)

Process
{
$WshShell = New-Object -ComObject wscript.Shell
$WshShell.Popup($Message, 0, $Titre)
}
}

La première chose que nous pouvons remarquer est l’utilisation de l ’attribut [CmdletBinding()]. Ensuite, dans le 
bloc  Param,  nous  avons  « décoré »  (c’est  ainsi  que  l’on  dit  dans  le  jargon)  chaque  paramètre d’un  attribut 
[Parameter()].  

Celui­ci  est  très  important  car  c’est  grâce  à  ce  dernier  que  l’on  définit  la  nature  du  paramètre,  c’est­à­dire  si  le 
paramètre  revêt  un  caractère  obligatoire  ou  facultatif,  s’il  doit  être  compris  entre  telle  et  telle  valeur,  etc.  Dans 
notre  exemple,  nous  avons  rendu  le  paramètre  -titre  obligatoire.  De  plus,  grâce  à  l’attribut 
[ValidateLength(1,10)], nous avons fait en sorte qu’il n’accepte que des valeurs comprises entre un et dix 
caractères.  En  faisant  cela,  nous  nous  assurons  que  la  fonction  ne  s’exécutera  pas  si  la  valeur  saisie  n’est  pas 
correcte. 

Nous insistons sur le fait que cette faculté de validation sur les valeurs de paramètres est vraiment très utile car 
elle permet de faire en sorte que le scripteur n’ait pas à se soucier des valeurs saisies. Ainsi, ce dernier pourra se 
concentrer davantage sur les actions métier du script et non pas sur des détails annexes à faible valeur ajoutée et 
à haut risque d’erreur. 

Enfin,  vous  pouvez  remarquer  la  présence  du  bloc  Process.  Ici,  dans  notre  exemple,  nous  aurions  pu  tout 
simplement  nous  en  passer  car  notre  fonction  ne  prend  pas  en  charge  le  pipeline.  En  effet,  les  blocs  Begin, 
Process et End ne sont utiles que dans le cas où une fonction ou un script accepte le passage de données via le 
pipeline. 

Pour  plus  d’informations  sur  l’attribut  [Parameter()],  nous  vous  invitons  à  consulter  la  rubrique  d’aide 
about_Functions_Advanced_Parameters. 

b. Attributs de validation des paramètres

Les  attributs  de  validation  des  paramètres,  appelés  également  « décorateurs », sont  une  grande  force  pour  les 
fonctions avancées car ils permettent de valider les valeurs saisies. Afin de vous servir d’aide­mémoire, nous avons 
regroupé tous les décorateurs dans le tableau ci­après : 

Attribut de validation d’un paramètre  Description 

[Alias(<String[]>)]  Définit un ou plusieurs alias sur un paramètre. 
Syntaxe : 
Param(
[Alias("CN","MachineName")]
[String]$ComputerName
)

[AllowNull()]  Indique  que  le  paramètre  accepte  une  valeur  nulle  (ce  qui 
n’est  pas  le  cas  par  défaut).  Cet  attribut  est  en  principe 
toujours associé à un paramètre obligatoire. 
Syntaxe : 

Param(
[Parameter(Mandatory=$true)]
[AllowNull()]
$Age
)

[AllowEmptyString()]  Cet  attribut  est  une  variante  de  l’attribut 


[AllowNull
()]. Il indique que l’on autorise une chaîne vide ("") comme 
valeur  de  paramètre.  Celui­ci  n’a  de  sens  qu’avec  un 
paramètre obligatoire, car un paramètre obligatoire n’autorise 
pas de chaînes vides. 
Syntaxe : 

Param (
[Parameter(Mandatory=$true)]
[AllowEmptyString()]
$Name
)

[AllowEmptyCollection()]  Variante  également  de  l’attribut 


[AllowEmptyString
()], cet attribut indique que l’on autorise une collection vide 
comme  valeur  de  paramètre.  Celui­ci  n’a  de  sens  qu’avec  un 
paramètre obligatoire, car un paramètre obligatoire n’autorise 
pas de chaînes vides. 
Syntaxe : 

Param (
[Parameter(Mandatory=$true)]
[AllowEmptyCollection()]
$ComputerName
)

[ValidateNotNull()]  Permet de spécifier que la valeur passée en argument ne doit 
pas  être  nulle.  C’est  le  contraire  de  l’attribut  [AllowNull
()]. 
Syntaxe : 

Param (
[Parameter(Mandatory=$true)]
[ValidateNotNull()]
$ComputerName
)

[ValidateNotNullOrEmpty()]  Spécifie  que  la  valeur  passée  en  argument  ne  doit  pas  être 
nulle ou vide.  
Syntaxe : 

Param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$ComputerName
)
[ValidateCount(<int>,<int>)]  Indique  un  nombre  minimal  et  maximal  de  valeurs  que  l’on 
peut fournir au paramètre. 
Syntaxe : 

Param(
[Parameter(Mandatory=$true)]
[ValidateCount(1,5)]
[String[]]
$ComputerName
)

Dans  cet  exemple  seront  acceptées  une  à  cinq  valeurs 


uniquement. 

[ValidateLength(<int>,<int>)]  Définit la longueur minimale et maximale de la valeur passée 
en paramètre (nombre de caractères par exemple). 
Syntaxe : 

Param(
[Parameter(Mandatory=$true)]
[ValidateLength(2,10)]
[String]
$ComputerName
)

Dans  cet  exemple,  un  nom  d’ordinateur  devra  avoir  de  deux 
à dix caractères. 

[ValidatePattern(<Regex>)]  Permet  de  s’assurer  que  la  valeur  passée  en  paramètre  est 
conforme à un modèle établi avec les expressions régulières. 
Syntaxe : 

Param(
[Parameter(Mandatory=$true)]
[ValidatePattern(’ˆ\w{6}\d{4}$’)]
[String[]]
$ComputerName
)

Dans  cet  exemple,  chaque  nom  d’ordinateur  passé  en 


paramètre  doit  commencer  par  6  lettres  suivies  de  4 chiffres, 
tel que : WinSRV1234 ou SrvXyz1234. 

[ValidateRange(<int>,<int>)]  Permet de s’assurer que la valeur passée en paramètre a été 
choisie parmi une plage de valeurs (minimale et maximale). 
Syntaxe : 

Param(
[Parameter(Mandatory=$true)]
[ValidateRange(0,100)]
[Int]
$Nb
)

Dans  cet  exemple,  la  valeur  du  paramètre  devra  être 


comprise entre 0 et 100. 

[ValidateSet(<String[]>)]  Permet de s’assurer que la valeur passée en paramètre a été 
choisie parmi une liste de valeurs prédéfinie. 
Syntaxe : 

Param(
[Parameter(Mandatory=$true)]
[ValidateSet("Rouge", "Bleu", "Vert")]
[String]
$Couleur
)

Dans cet exemple, la valeur du paramètre doit être « rouge », 


« bleu » ou « vert » pour être acceptée. 

[ValidateScript({ScriptBlock})]  Un  bloc  de  script  est  utilisé  pour  valider  la  valeur  fournie  en 
paramètre.  Pour  que  la  valeur  soit  acceptée,  le  bloc  de  script 
doit retourner la valeur  $true. 
Syntaxe : 

Param(
[Parameter()]
[ValidateScript({$_ -ge (Get-Date)})] [DateTime]
$EventDate
)

Dans  cet  exemple,  pour  que  la  valeur  du  paramètre  soit 
acceptée,  il  faut  que :  1)  elle  soit  de  type  DateTime  et  2) 
qu’elle soit supérieure ou égale à la date courante. 
Scripts

Les  scripts  ont  un  fonctionnement  identique  aux  fonctions  dans  le  sens  où  ils  peuvent  eux  aussi  bénéficier  de 
l’attribut  [CmdletBinding]  et  de  tout  ce  qui  caractérise  les  fonctions  avancées,  prendre  en  charge  des  paramètres, 
proposer une aide intégrée (voir plus loin), etc. La vision de Microsoft et en particulier de l’équipe PowerShell est de 
permettre aux développeurs PowerShell de réaliser des scripts qui se comportent exactement comme des commandes 
PowerShell natives. 

D’autre  part,  les  scripts  PowerShell  constituent  l’enveloppe  physique  qui  contient  généralement  des  variables,  ainsi 
qu’un ensemble de fonctions. Ils portent l’extension .ps1. 

Quelle que soit la version de PowerShell, même avec la version 6, tous les scripts portent l’extension .ps1.  

1. Constitution d’un script

Un script est généralement constitué des parties suivantes : 

# Nom du script, auteur, version, etc.


Déclaration des paramètres
...

Déclaration des fonctions


...

Corps principal du script


...

Ceci étant, dans sa forme la plus minimaliste, un script ne peut contenir que le corps principal, le reste n’étant pas 
obligatoire.  Généralement,  on  va  trouver  sur  les  premières  lignes  d’un  script  quelques  commentaires  décrivant 
succinctement : 

l Le nom du script, 

l Un numéro de version, 

l La date de création, 

l Le nom de l’auteur. 

Bonne  pratique :  Si  vous  souhaitez  apporter  d’autres  informations  plus  précises  sur  le 
fonctionnement  du  script,  par  exemple  sur  l’usage  de  ses  paramètres,  ainsi  qu’éventuellement 
proposer quelques  exemples  d’utilisation,  nous  vous  recommandons  de  fournir  une  aide  structurée 
telle que définie dans la section Aide intégrée aux scripts et fonctions. Ainsi, l’aide sera disponible à tous 
vos utilisateurs en tapant la ligne de commandes suivante : help MonScript.ps1. Tout script digne de 
ce nom, en entreprise, se doit de proposer une aide intégrée. 

2. Commentaires

Vous  le  savez  sans  doute  déjà,  de  par  les  différents  exemples  que  nous  avons  fournis,  les  commentaires 
commencent toujours par le caractère dièse « # ». Un commentaire peut être placé à n’importe quel endroit dans un 
script.  
Par exemple : 

# MonScript.ps1

# Déclaration des variables


[int]$nbFic = 0 # nombre d’objets du répertoire courant

# Début du script
$nbFic = (Get-Childitem).count

$nbFic # retourne le résultat trouvé

Il est possible aussi de créer des blocs de commentaires grâce à la syntaxe suivante : 

<#
Tout ce qui se trouve à l’intérieur d’un bloc
de commentaires est ignoré
#>

Les blocs de commentaires sont très pratiques pour commenter un grand nombre de lignes à l’intérieur d’un script. 
Cela évite de devoir placer un dièse devant chaque ligne à commenter. 

3. Exécution d’un script

Cela  peut  sembler  surprenant  au  premier  abord,  mais  il  faut  savoir  que  l’exécution  des  scripts  PowerShell  est 
désactivée  par  défaut  sur  toutes  les  versions  clientes  de  Windows.  Par  contre,  sous  Windows  Server,  à  partir  de 
Windows Server 2012 R2 l’exécution est autorisée, mais seulement sous certaines conditions. 

Si tel n’est pas le cas sur votre ordinateur, c’est que l’administrateur de votre entreprise a probablement configuré 
une stratégie de groupe (GPO) pour autoriser l’exécution des scripts. 

Pour déterminer si vous pouvez ou non exécuter des scripts, vous pouvez au choix, soit : 

l Tenter l’exécution d’un script et observer le résultat, 

l Utiliser la commande Get-ExecutionPolicy afin de déterminer la stratégie d’exécution courante. 

Si le résultat d’exécution de la commande  Get-ExecutionPolicy est  Restricted, c’est que vous ne pouvez 


pas exécuter de scripts.  

L’exécution de commandes PowerShell tapées directement dans la console (mode interactif) est autorisée quelle que 
soit la stratégie d’exécution. 

Pour modifier la stratégie d’exécution courante, il faut : 

l Démarrer la console en mode Administrateur (clic droit sur l’icône PowerShell, puis Run as Administrator), 

l Taper la commande Set-ExecutionPolicy RemoteSigned. 
La  stratégie  RemoteSigned  autorise  uniquement  l’exécution  des  scripts  locaux  ;  les  scripts  en  provenance  d’un 
serveur en dehors de votre zone de confiance intranet tels que ceux venant d’Internet seront quant à eux bloqués. 
Pour en savoir plus sur la sécurité en général, mais aussi sur les autres stratégies d’exécution disponibles, veuillez 
vous reporter au chapitre Sécurité.  

4. La directive #Requires

La  directive #Requires  permet  de  s’assurer  de  l’existence  de  certains  prérequis  afin  de  permettre  l’exécution d’un 
script.  

Ainsi il est possible de s’assurer : 

l Que PowerShell s’exécute dans une version minimale, 

l Que PowerShell s’exécute dans une édition spécifique (Desktop ou Core), 

l Que PowerShell s’exécute en mode Administrateur, 

l De la présence de certains modules et snap­ins ainsi que de leur numéro de version. 

Les différents cas d’usages sont les suivants : 

#Requires -Version <N>[.<n>]


#Requires -PSEdition [ Core | Desktop ]
#Requires -PSSnapin <PSSnapin-Name> [-Version <N>[.<n>]]
#Requires -Modules { <Module-Name> | <Hashtable> }
#Requires -ShellId <ShellId>
#Requires -RunAsAdministrator

Exemple :  

Soit le début du script suivant : 

#Requires -Version 5
#Requires -Modules PSWorkflow,
@{ModuleName="DataOnTap";ModuleVersion=3.2.0.0}
#Requires -PSSnapin DiskSnapin -Version 1.2
#Requires -RunAsAdministrator

Nous avons volontairement forcé un peu le trait, car il est rare de vérifier autant de prérequis à la fois, cependant 
sachez  que  vous  pouvez  spécifier  plusieurs  directives  #Requires  dans  un  même  script.  Les  directives  doivent 
systématiquement apparaître en début de ligne et commencer par un dièse. 

Les numéros de version que nous avons spécifiés tant pour le snap­in que pour le module sont facultatifs.  

5. Prise de conscience de l’environnement d’exécution (contexte)

Certaines informations peuvent se révéler précieuses lors de l’exécution d’un script, telles que : 

l l’emplacement du script courant, 
l le nom du script courant, 

l la ligne de commandes complète qui a permis l’exécution du script, 

l etc. 

Lorsque nous développons des scripts d’une certaine envergure, il est souvent nécessaire de générer des fichiers 
de logs, et pouvoir « logguer » la ligne de commandes complète (avec les paramètres) ayant permis l’exécution d’un 
script est parfois d’une importance capitale. 

Pour ce faire, PowerShell met à notre disposition de nombreuses variables automatiques. Celles­ci sont récapitulées 
dans le tableau ci­dessous : 

Variable  Description 

$PSCommandPath  Contient le chemin complet du script courant. 

$PSScriptRoot  Contient  le  répertoire  dans  lequel  se  trouve  le  script 
courant. 

$MyInvocation  Objet  contenant  l’intégralité  du  contexte  d’exécution 


courant. 

$MyInvocation.MyCommand.Path  Idem  $PSCommandPath. 

$MyInvocation.MyCommand.line  Contient  la  ligne  de  commandes  complète ayant 


permis  l’exécution  du  script  (incluant  tous  les 
paramètres). 

$MyInvocation.PSCommandPath  Contient  le  chemin  complet  du  script  parent ayant 


permis d’appeler un script enfant (cet objet ne contient 
une valeur que si l’appel au script enfant s’effectue au 
travers d’un script parent). 

$MyInvocation.PSScriptRoot  Contient  le  répertoire  dans  lequel  se  trouve  le  script 
parent  ayant  permis  d’appeler un  script  enfant  (cet 
objet  ne  contient  une  valeur  que  si  l’appel  au  script 
enfant s’effectue au travers d’un script parent). 

Comme  vous  pouvez  le  voir,  il  n’est  pas  évident  de  s’y  retrouver  étant  donné  toutes  les  variables  à  notre 
disposition.  Des  exemples  valant  mieux  qu’un  long  discours,  créons  le  petit  script  suivant  que  nous  appellerons 
testInvocation.ps1 et que nous stockerons dans l’emplacement C:\Temp : 

# testInvocation.ps1
Param ($a, $b, $c)

"`$PSCommandPath = $PSCommandPath"
"`$PSScriptRoot = $PSScriptRoot"
"`$MyInvocation.MyCommand.Path = $($MyInvocation.MyCommand.Path)"
"`$MyInvocation.MyCommand.line = $($MyInvocation.line)"
"`$MyInvocation.PSCommandPath = $($MyInvocation.PSCommandPath)"
"`$MyInvocation.PSScriptRoot = $($MyInvocation.PSScriptRoot)"
$MyInvocation | Format-List * -force

Ce script va nous montrer le contenu de chacune de ces variables et cela va nous aider à mieux comprendre le rôle 
de ces dernières. 

À présent, positionnons­nous dans un autre répertoire que le répertoire où se trouve le script, par exemple dans le 
répertoire C:\Program Files, et exécutons le script testInvocation.ps1 de la façon suivante : 
PS > ..\Temp\testinvocation.ps1 -a ’Bonjour’ -b 22

$PSCommandPath = C:\Temp\testInvocation.ps1
$PSScriptRoot = C:\Temp
$MyInvocation.MyCommand.Path = C:\Temp\testInvocation.ps1
$MyInvocation.MyCommand.line = ..\Temp\testinvocation.ps1 -a
’Bonjour’ -b 22
$MyInvocation.PSCommandPath =
$MyInvocation.PSScriptRoot =

MyCommand : testInvocation.ps1
BoundParameters : {[a, Bonjour], [b, 22]}
UnboundArguments : {}
ScriptLineNumber : 1
OffsetInLine : 1
HistoryId : 194
ScriptName :
Line : ..\Temp\testinvocation.ps1 -a ’Bonjour’ -b 22
PositionMessage : At line:1 char:1
+ ..\Temp\testinvocation.ps1 -a ’Bonjour’ -b 22
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PSScriptRoot :
PSCommandPath :
InvocationName : ..\Temp\testinvocation.ps1
PipelineLength : 1
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Runspace
DisplayScriptPosition :

On  se  rend  immédiatement  compte  que  l’objet  $MyInvocation.MyCommand.Path  contient  l’emplacement 
absolu  complet  du  script  courant  et  que,  mieux  encore,  l’objet  $MyInvocation.MyCommand.line  contient  la 
ligne de commandes qui a permis l’exécution du script.  

Nous  pouvons  aussi  remarquer  que  $MyInvocation.PSCommandPath  et 


$MyInvocation.PSScriptRoot sont vides pour le moment. C’est normal dans la mesure où nous avons fait un 
appel direct, c’est­à­dire depuis l’invite de commandes. 

Voyons  ce  qu’il  se  passe  maintenant  si  nous  créons  un  second  script  dont  le  rôle  est  d’exécuter 
testInvocation.ps1.  Nous  appellerons  ce  script  lanceur.ps1  et  nous  l’enregistrerons  dans  le  répertoire 
Documents. 

# lanceur.ps1
& C:\Temp\testinvocation.ps1 -a 2 -b 1

À  présent,  positionnons­nous  à  la  racine  du  disque  C:\  et  tapons  la  commande 
C:\Users\Administrateur\Documents\lanceur.ps1 pour exécuter le script, tel que ci­dessous : 
PS > C:\Users\Administrateur\Documents\lanceur.ps1

$PSCommandPath = C:\Temp\testinvocation.ps1
$PSScriptRoot = C:\Temp
$MyInvocation.MyCommand.Path = C:\Temp\testinvocation.ps1
$MyInvocation.MyCommand.line = & C:\Temp\testinvocation.ps1 -a 2 -b 1

$MyInvocation.PSCommandPath = C:\Users\Administrator\Documents\lanceur.ps1
$MyInvocation.PSScriptRoot = C:\Users\Administrator\Documents

MyCommand : testinvocation.ps1
BoundParameters : {[a, 2], [b, 1]}
UnboundArguments : {}
ScriptLineNumber : 2
OffsetInLine : 1
HistoryId : 15
ScriptName : C:\Users\Administrator\Documents\lanceur.ps1
Line : & c:\Temp\testinvocation.ps1 -a 2 -b 1

PositionMessage : At C:\Users\Administrator\Documents\lanceur.ps1:2
char:1

+ & c:\Temp\testinvocation.ps1 -a 2 -b 1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PSScriptRoot : C:\Users\Administrateur\Documents
PSCommandPath : C:\Users\Administrateur\Documents\lanceur.ps1
InvocationName : &
PipelineLength : 1
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Internal
DisplayScriptPosition :

$MyInvocation.PSCommandPath  et  $MyInvocation.PSScriptRoot  sont  cette  fois­ci  bel  et  bien 


renseignés et contiennent tous deux des informations sur le script parent ayant permis l’exécution du script enfant.  

6. Internationalisation

Dans  la  version  1  de  PowerShell,  l’édition  de  scripts  destinés  à  un  public  constitué  de  personnes  de  nationalités 
différentes n’était pas chose évidente car le scripteur se devait de traduire manuellement tout le contenu textuel de 
ses scripts. Dans PowerShell v2 est apparu ce qu’on appelle « l’internationalisation de script » et cette fonctionnalité 
n’a  pas  évolué  avec  les  versions  suivantes  de  PowerShell.  Le  principe  de  l’internationalisation  est  de  permettre 
l’écriture de scripts en différentes langues sans pour autant modifier le code contenu dans les scripts. Par exemple, 
si  vous  créez  un  script  et  que  celui­ci doit être exécuté par plusieurs personnes, chacune utilisant une version de 
PowerShell  différente  en  termes  de  langue  (variable  $PSUICulture  différente), le  fait  d’utiliser 
l’internationalisation permettra aux utilisateurs d’obtenir toute la partie textuelle du script dans leur langue, et ce, 
sans aucune manipulation de leur part. Regardons à présent comment cela fonctionne. 

La  première  précaution  à  prendre  est,  bien  évidemment,  de  séparer  les  données  (data)  du  code  contenu  dans  le 
script.  
Pour  ce  faire,  nous  utilisons  une  section  Data.  Et  c’est  à  l’intérieur  de  cette  section  que  nous  utilisons  la 
commandelette ConvertFrom-StringData, qui va créer une table de hachage des chaînes de caractères. 

Exemple 

$TexteScript = Data {
ConvertFrom-StringData @’
Message_1 = Bonjour
Message_2 = Entrez une valeur
Message_3 = Entrez une autre valeur
Message_4 = Le résultat de l’addition de ces deux valeurs est :
’@
}

Notez  que  nous  utilisons  ici  une  Here-String.  Une  Here-String  commence  avec  un  séparateur  @’  et  se 
termine par  ’@ (le dernier séparateur doit absolument être précédé d’un retour chariot). Tous les caractères entre 
les délimiteurs arobase sont considérés comme du texte. 

De façon à permettre la traduction des sections Data, une traduction en différentes langues doit être sauvegardée 
dans des fichiers .psd1 et sous une arborescence particulière.  

Les fichiers .psd1 se doivent d ’être enregistrés dans un sous­répertoire au format <langage>-<Pays>, comme 
l’indique  la  variable  $PSUICulture.  Ainsi,  si  le  script  principal  nommé  MonScript.ps1  se  trouve  dans  le 
répertoire C:\Temp, les fichiers MonScript.psd1 se trouveront sous l’arborescence suivante : 

C:\Temp\MonScript.ps1 # Script Principal


C:\Temp\en-US\MonScript.psd1 # Fichier des données traduites en anglais
C:\Temp\es-ES\MonScript.psd1 # Fichier des données traduites en espagnol
...

Exemple de contenu des fichiers .psd1 

Fichier C:\Temp\en­US\MonScript.psd1 : 

ConvertFrom-StringData @’
Message_1 = Hello
Message_2 = Enter a value
Message_3 = Enter a second value
Message_4 = The result of the addition of these two values is:
’@

Fichier C:\Temp\es­ES\MonScript.psd1 : 

ConvertFrom-StringData @’
Message_1 = Hola
Message_2 = Introducid un valor
Message_3 = Introducid un segundo valor
Message_4 = El resultado de la adición de estos dos valores
es la siguiente:
’@

Enfin, dernière étape, permettre l’importation des chaînes de caractères dans la langue de l’interface utilisateur via 
la  commandelette  Import-LocalizedData.  L’utilisation  de  cette  commandelette  importe  le  fichier  .psd1 
correspondant à la langue utilisée, et rend transparentes les actions de traduction des éléments textuels du script. 
Le script complet devient le suivant : 

$TexteScript = Data {
#Culture fr-FR
ConvertFrom-StringData @’
Message_1 = Bonjour
Message_2 = Entrez une valeur
Message_3 = Entrez une autre valeur
Message_4 = Le résultat de l’addition de ces deux valeurs est :
’@
}

Import-LocalizedData TexteScript

# Début du script

Write-Host $TexteScript.Message_1
Write-Host $TexteScript.Message_2
[int]$var1 = Read-Host
Write-Host $TexteScript.Message_3
[int]$var2 = Read-Host
$resultat = $var1 + $var2
Write-Host "$($TexteScript.Message_4) $resultat"

# Fin du script

En exécutant le script précédent sur un poste Windows version US, nous obtenons le résultat suivant : 
 

PS > C:\Temp\MonScript.ps1
Hello
Enter a value
5
Enter a second value
6
The result of the addition of these two values is: 11
La gestion de fichiers
La gestion des fichiers est très simple avec PowerShell, contrairement à VBScript, pour ceux qui ont eu l’occasion de le 
pratiquer.  En  effet,  il  n’est  plus  question  d’instancier  des  objets  COM  de  type  filesystem,  de  les  ouvrir  en 
spécifiant  un  mode  d’accès  (lecture  ou  écriture),  puis  de  les  fermer.  PowerShell  apporte  un  jeu  de  commandelettes 
dédié à la gestion de fichiers et nous verrons que cela représente un énorme gain de productivité dans l’écriture des 
scripts.  

Cela étant, il y a un point particulier sur lequel il est important d’être vigilant et de savoir ce que l’on fait si l’on veut 
s’éviter bien des problèmes. Il s’agit du format d’encodage des fichiers texte. Ils sont nombreux et il ne faut pas se 
tromper ; nous détaillerons donc ce point dans ce présent chapitre. 

Dans le chapitre À la découverte de PowerShell, nous nous étions intéressés au contenant, c’est­à­dire au fichier lui­
même,  et  nous  avions  vu  comment  les  créer,  les  déplacer,  les  renommer,  etc.  À  présent,  intéressons­nous  au 
contenu, et voyons entre autres comment le générer et comment le relire. 

1. Formats d’encodage des fichiers texte

Avant d’entrer dans le vif du sujet, il nous paraît nécessaire de prendre quelques minutes pour faire le point sur ce 
vaste et important sujet qu’est l’encodage des fichiers texte. 

Sans entrer dans les détails de la préhistoire de l’informatique, commençons avec le standard ASCII, bien connu de 
tous. Celui­ci, apparu avec les premiers ordinateurs à la fin des années 60 aux États­Unis, encode les caractères sur 
7 bits (de la position 0 à 127), soit un total de 128 caractères que l’on a regroupés dans une table qui fut devenue 
célèbre,  c’est  la  fameuse  table  ASCII.  Le  souci  de  cette  norme,  pour  nous  Français  (mais  pas  seulement),  c’est 
qu’elle  ne  contient  pas  nos  chers  caractères  accentués…  Ce  qui  est  logique  puisque  l’ASCII  a  été  inventé  par  un 
organisme américain pour les Américains. 

L’ASCII étendu (ANSI), une solution intermédiaire 

Comme à tout problème, toute solution, et qu’en informatique les processeurs travaillent sur des puissances de 2, il 
n’était  pas  possible  d’écrire  un  caractère  autrement  que  sur  8  bits  (1  octet).  Il  y  avait  donc  un  bit  inutilisé  dans 
l’encodage des caractères au format ASCII. Les informaticiens de l’époque ont alors décidé d’utiliser ce dernier bit 
pour  étendre  la  table  ASCII  afin  de  pouvoir  y  stocker  les  caractères  accentués  des  différentes  langues.  Cette 
technique a donné naissance au format ASCII étendu, également connu sous l’appellation ANSI. Il fut donc créé ce 
que l’on appela des « pages de codes » afin de stocker les caractères accentués de la langue française, espagnole, 
allemande, et autres. Bien que relativement efficace, cette solution a ajouté un peu de complexité de configuration 
car, en fonction de la langue, il fallait choisir la page de codes adéquate.  

Le  monde  a  fonctionné  ainsi  durant  de  nombreuses  années  jusqu’au  début  des  années  1990  et  l’arrivée  de 
l’Internet, qui a tout révolutionné en repoussant nos frontières. En effet, il a fallu trouver des moyens pour que les 
ordinateurs soient capables de prendre en charge plusieurs langues simultanément. En effet, qui aurait accepté que 
les caractères accentués français ne s’affichent pas correctement sur un système d’exploitation anglais, espagnol ou 
chinois  et  réciproquement !?  C’est  alors  que  le  standard  Unicode  a  fait  son  apparition  et  que  les  choses  se  sont 
corsées d’avantage d’un point de vue technique… 

L’Unicode et ses variantes 

Unicode  s’est  très  rapidement  imposé  comme  une  solution  efficace  aux  problèmes  d’encodage.  Seulement  voilà,  il 
existe d’innombrables formats Unicode ainsi que de nombreuses variantes. Nous avons mis dans le tableau ci­après 
les formats les plus courants que nous serons à même de manipuler avec PowerShell : 
Format Unicode  Type  Poids d’un caractère 
d’encodage 

UTF­8  8 bits  8  bits  pour  un  caractère  « standard »,  variable  pour  les  caractères 
accentués. 

UTF­16  16 bits  16 bits 

UTF­32  32 bits  32 bits 

On peut également trouver de l’UTF­7, mais ce format n’a jamais fait partie officiellement du standard. De plus, pour 
nous  Français,  il  n’a  aucun  intérêt  dans  la  mesure  où  nous  ne  pouvons  pas  l’utiliser  pour  encoder  nos  accents. 
Quant  à  l’UTF­16  et  l’UTF­32,  vous  l’aurez  compris,  ils  nécessitent  respectivement  2  et  4  octets  pour  stocker un 
caractère,  ce  qui  fera  indubitablement  doubler  ou  quadrupler  la  taille  des  fichiers  encodés  dans  ces  formats  par 
rapport à de l’ASCII pur ou à de l’ASCII étendu. 

Quant à l’UTF­8, cet encodage est intéressant car tous les caractères standards, c’est­à­dire ceux de la table ASCII, 
sont  encodés  sur  8  bits,  tandis  que  les  caractères  spéciaux  (tous  les  autres)  peuvent  être  encodés  sur  deux  à 
quatre octets (ce qui laisse de la marge). Ce format est donc assez bien équilibré car il permet d’encoder la plupart 
des caractères de la planète tout en gardant une taille compacte. 

Gros Indien ou petit Indien ? 

Revenons un instant sur les formats UTF­16 et UTF­32. Ceux­ci encodant les caractères sur plusieurs octets, se pose 
alors inévitablement la question de l’ordre de disposition des octets. Faut­il écrire l’octet de poids fort avant l’octet 
de poids faible ou l’inverse ? C’est un peu comme si tous les humains de la planète parlaient une langue commune 
mais que certains pays écrivaient cette langue sur papier de la droite vers la gauche alors que d’autres l’écrivaient 
de  la  gauche  vers  la  droite.  En  informatique,  cette  notion  qui  définit  l’ordre d’encodage  des  octets  des  caractères 
s’appelle l’endianness ; il n’y a pas à notre connaissance de terme francophone correspondant. 

On  distingue  deux  variantes  d’encodage  Unicode  que  sont  Little  Endian  et  Big  Endian.  La  plupart  des  OS  actuels 
(Windows, Linux, Mac OS) ont adopté la norme Little Endian, mais certains travaillent encore avec Big Endian (HP­
UX, AIX, iSeries, zSeries, etc.).  

Byte Order Mark (BOM) des fichiers Unicode 

Enfin, pour clore cette mise au point sur les différents formats d’encodage des fichiers texte, il ne nous reste plus 
qu’à aborder la notion de Byte Order Mark (BOM), souvent traduit par Indicateur d’Ordre des Octets (IOO).  

Le  BOM  est  une  suite  de  quelques  octets  qui  permet  d’indiquer  le  format  d’encodage  d’un  fichier  texte.  Le  BOM, 
lorsqu’il  est  présent,  se  place  toujours  au  début  d’un  fichier. Il  permet  d’indiquer  aux  programmes  tels  que  les 
éditeurs de texte dans quel format se trouve un fichier afin de l’ouvrir correctement.  

Format Unicode  Byte Order Mark 

UTF­8  EF BB BF 

UTF­16  FF FE 

UTF­32  FF FE 00 00 

Afin  d’alléger  le  tableau,  les  BOM  indiqués  ici  le  sont  pour  la  variante  Little  Endian,  étant  celle  par  défaut  sur  un 
système Windows.  

Souvenez­vous que la notion d’Endianness ne s’applique qu’aux formats Unicode UTF­16 et UTF­32. 
Pour visualiser le BOM d’un fichier texte, nous pouvons faire appel à la commande Format-Hex. 

Exemple : BOM d’un fichier UTF­8 

PS > ’É-ù-è-é’ | Out-file ./UTF8BOM.txt -Encoding utf8BOM


PS > Format-Hex -Path .\UTF8BOM.txt

Path: C:\temp\UTF8BOM.txt

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000 EF BB BF C3 89 2D C3 B9 2D C3 A8 2D C3 A9 0D 0A É-ù-è-é..

La commande Format-Hex est extrêmement pratique car elle permet de lire le contenu de n’importe quel type de 
fichiers. Elle se comporte un peu à la manière d’un éditeur héxadécimal, sauf qu’on ne peut pas éditer le contenu. 
On pourrait donc l’assimiler à un visualiseur héxadécimal.  

Essayons­la avec un autre type de fichier, tel qu’un fichier PDF. 

PS > Format-Hex -Path .\MANUEL_V2.pdf | Select-Object -First 10

Path: C:\temp\MANUEL_V2.pdf

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000 25 50 44 46 2D 31 2E 36 0D 25 E2 E3 CF D3 0D 0A %PDF-1.6.%âãÏÓ..
00000010 34 34 32 36 20 30 20 6F 62 6A 20 3C 3C 2F 4C 69 4426 0 obj <</Li
00000020 6E 65 61 72 69 7A 65 64 20 31 2F 4C 20 38 39 36 nearized 1/L 896
00000030 37 38 30 31 2F 4F 20 34 34 33 31 2F 45 20 31 31 7801/O 4431/E 11
00000040 38 30 38 38 2F 4E 20 31 33 38 2F 54 20 38 38 37 8088/N 138/T 887
00000050 39 32 31 35 2F 48 20 5B 20 34 34 30 36 20 33 32 9215/H [ 4406 32
00000060 33 38 5D 3E 3E 0D 65 6E 64 6F 62 6A 0D 20 20 20 38]>>.endobj.
00000070 20 20 0D 0A 78 72 65 66 0D 0A 34 34 32 36 20 32 ..xref..4426 2
00000080 30 30 0D 0A 30 30 30 30 30 30 30 30 31 36 20 30 00..0000000016 0
00000090 30 30 30 30 20 6E 0D 0A 30 30 30 30 30 30 37 38 0000 n..00000078

Notez que pour limiter le nombre de lignes de résultat, nous avons fait appel à la commande Select-Object. 

Il faut savoir que les quelques premiers octets d’un fichier binaire permettent toujours d’identifier le 
type d’un  fichier.  C’est  sa  signature.  On  appelle  cela  également  le  « nombre magique »  ou « magic 
number » en anglais. Dans le cas d’un fichier PDF, sa signature est la suite d’octets 25, 50, 44, 46. 

2. Différences Windows PowerShell 5.x / PowerShell Core

Par  le  passé,  l’équipe  de  développement  de  PowerShell  n’avait  pas  été  très  rigoureuse  quant  à  l’encodage  des 
fichiers  générés  par  les  différentes  commandes  PowerShell  qui  produisent  des  fichiers  texte.  Par  exemple,  par 
défaut  avec  Windows  PowerShell  5.x,  la  commande  Out-File  encode  les  fichiers  en  UTF­16  tandis  que  la 
commande  Export-CSV  les  crée  en  UTF­8  alors  que  la  commande  Set-Content  les  génère  en  ANSI.  Cette 
disparité  dans  les  formats  d’encodage  a  créé  beaucoup  de  confusion  et  donné  du  fil  à  retordre  à  de  nombreux 
scripteurs… Heureusement, cette époque est révolue ! À présent, PowerShell Core corrige les erreurs du passé et 
tous les fichiers générés par les différentes commandes le sont en Unicode UTF­8 sans BOM. 

Pourquoi  sans  BOM,  nous  direz­vous ?  Eh  bien  tout  simplement  parce  que  la  plupart  des  plateformes  autres  que 
Windows utilisent ce format d’encodage par défaut. PowerShell Core étant multiplateforme, c’est donc ce format qui 
l’a emporté. De plus, la plupart des outils et applications Windows migrent peu à peu vers cet encodage. 

Dernier  point  de  vigilance :  faites  très  attention  lorsque  vous  utilisez  le  paramètre  -Encoding  car  les  valeurs 
peuvent légèrement différer d’une commande à l’autre avec Windows PowerShell. De plus, entre PowerShell Core et 
Windows PowerShell, pour ce même paramètre les valeurs ne sont pas exactement les mêmes. Nous entrons donc 
ici dans une zone où il peut donc y avoir potentiellement des problèmes de compatibilité entre ces deux éditions de 
PowerShell. La prudence est donc de mise… 

3. Bonnes pratiques

Prenez garde au format d’encodage de vos fichiers texte ! Ce précieux conseil vous évitera bien des maux de tête. 
D’une  manière  générale,  lorsque  vous  créez  un  fichier  avec  quelque  commande  que  ce  soit,  nous  vous 
recommandons  de  toujours  préciser  son  encodage grâce  au  paramètre  -Encoding.  Ce  conseil  prend  tout  son 
sens avec Windows PowerShell (voir partie précédente) ! 

En termes de choix du format d’encodage, le format UTF­8 constitue une option intéressante car il est compact et 
permet d’encoder tous les caractères spéciaux de la langue française (mais pas seulement). 

4. Écriture de données dans un fichier

Il y a deux façons essentielles de procéder pour écrire des données dans un fichier. Nous pouvons utiliser soit Set-
Content, soit Out-File. 

Bien que ces deux commandes servent à faire la même chose : créer des fichiers et des données, il y a cependant 
une différence notable qu’il est important de connaître mais qui n’est pas facilement décelable. 

Lorsque  Out-File est utilisée, cette commande tente, tout comme les autres commandes Out-*, de formater le 
flux avant de l’écrire dans le fichier. 

Set-Content  quant  à  elle,  ne  cherche  pas  à  formater  le  flux  mais  elle  lui  applique  seulement  la  méthode 
ToString()  afin  d’être  sûre  d’écrire  des  caractères.  C’est  cela  la  principale  différence.  Cependant,  bien  qu’elle 
puisse  sembler  anodine,  vous  aurez  des  surprises  si  vous  tentez  d’écrire  un  objet  dans  un  fichier  avec  Set-
Content sans l’avoir formaté au préalable. 

Par exemple, le résultat de cette commande écrit dans un fichier le nom du type de l’objet au lieu de son contenu : 

PS > Get-Process powershell | Set-Content .\MonFichier.txt


PS > Get-Content .\MonFichier.txt

System.Diagnostics.Process (powershell)

Alors que la commande suivante nous donne le résultat attendu : 

PS > Get-Process powershell | Out-File .\MonFichier.txt


PS > Get-Content .\MonFichier.txt

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ ---- -----------
533 13 64608 65376 219 38,39 2080 powershell

Pour  obtenir  le  même  résultat  avec  Set-Content,  il  aurait  fallu  effectuer  un  transtypage  préalable  sur  l’objet 
avant de l’écrire, comme ceci : 

PS > Get-Process powershell | Out-String -Stream |


Set-Content .\MonFichier.txt

Out-String  permet  de  convertir  les  objets  émis  en  les  représentant  sous  forme  de  chaîne.  Le  paramètre  -
Stream  permet  d’envoyer au pipeline autant de chaînes que d’objets reçus, au lieu d’envoyer une chaîne unique 
contenant la représentation de tous les objets. 

Si nous souhaitons personnaliser le résultat, nous pourrions écrire ceci : 

PS > Get-Process powershell | Format-Table id, processname |


Out-String -Stream | Set-Content MonFichier.txt

Une autre différence est que Out-File formate la sortie telle qu’elle est affichée dans la console. C’est­à­dire que 
Out-File ajoute les retours chariot et des sauts de ligne en fonction de la largeur de la fenêtre PowerShell, ce qui 
n’est pas le cas de Set-Content. 

Set-Content permet d’écrire directement des octets dans un fichier grâce au paramètre -Encoding Byte. La 


valeur  Byte de ce paramètre est propre à  Set-Content,  il  n’est pas possible d’utiliser cette valeur d’encodage 
avec  Out-File. Cela permet de manipuler des fichiers autres que des fichiers texte en écrivant directement des 
octets. 

En résumé, on aura plutôt tendance à privilégier l’utilisation de Out-File avec les fichiers texte, et à utiliser Set-
Content avec les fichiers binaires. 

a. Fichiers texte avec Out­File

Cette  commande  très  puissante  permet  de  créer  des  fichiers  avec  du  contenu. Elle  fait  sensiblement  la  même 
chose  que  les  opérateurs  de  redirection,  sauf  que  l’on  peut  spécifier  à  Out-File  un  certain  nombre  de 
paramètres, chose que l’on ne peut pas faire avec les opérateurs de redirection.  

Voici la liste des paramètres les plus couramment utilisés : 

Paramètre  Description 

-FilePath <String>  Fichier de destination. 

-Encoding <String>  Type d’encodage (défaut :  unicode). 

-Append <Switch>  Ajoute du contenu à un fichier existant. 

-NoClobber <Switch>  Indique de ne pas écraser un fichier existant.  

Les valeurs possibles pour le paramètre d’encodage -Encoding sont les suivantes : 
Nom  Description 

Ascii  Force  l’encodage  en  ASCII  de  base  (jeu  de  caractères  0  à  127,  7  bits). 
Attention,  ce  type  ne  contient  pas  les  caractères  accentués.  Pour  cela, 
préférez la valeur  Default ou un format Unicole. 

UTF7  Force l’encodage en Unicode  UTF7. 

UTF8  Force l’encodage en Unicode  UTF8. 

UTF8BOM*  Idem  UTF8. 

UTF8NoBOM*  Force l’encodage en Unicode  UTF8 sans BOM. 

Unicode  Force l’encodage en Unicode  UTF16 LittleEndian. 


BigEndianUnicode  Force l’encodage en Unicode  UTF16 BigEndian. 
UTF32  Force l’encodage en Unicode  UTF32 LittleEndian. 
Default  Utilise  le  codage  de  la  page  de  codes  ANSI  actuelle  du  système  (ASCII 
étendu). 

Oem  Utilise  l’identificateur  de  la  page  de  codes  du  fabricant  d’ordinateurs  OEM 
(Original Equipment Manufacturer) actuel pour le système d’exploitation. 

L’astérisque signifie que cette valeur n’est présente qu’avec PowerShell Core. 

Exemple 

Création d’un fichier ASCII contenant des informations sur un processus du système. 

PS > Get-Process powershell |


Out-File C:\Temp\Process.txt -Encoding ascii

Cette commande crée le fichier  ASCII monfichier.txt dans le répertoire  C:\Temp. Ce fichier contiendra le 


résultat d’exécution de la commande précédente passée au travers du pipeline. 

Exemple 2 

Ajout de données à un fichier existant. 

PS > Get-Date | Out-File C:\Temp\Date.txt -Append -Encoding ascii

Dans cet exemple, nous ajoutons des données au fichier que nous avons créé dans l’exemple  précédent.  Faites 


bien  attention  de  toujours  spécifier  le même  format  d’encodage lorsque  vous  ajoutez  des  données  à  un  fichier. 
PowerShell ne vous préviendra pas, mais si les formats de vos données diffèrent votre fichier deviendra illisible. 

Lorsque  vous  ajoutez  des  données  à  un  fichier  texte,  n’oubliez  jamais  de  tenir  compte  de  l’encodage  de  celui­ci, 
sous peine de rendre votre fichier illisible. Une méthode simple quand vous ne connaissez pas l’origine d’un  fichier 
et  que  vous  avez  des  données à  lui  ajouter,  est  de  l’ouvrir  dans  le  bloc­notes  et  de  faire  comme  si  vous  vouliez 
l’enregistrer  en  choisissant  l’option  Enregistrer  sous.  Ainsi  dans  le  bas  de  la  fenêtre,  vous  pourrez  voir  une  liste 
déroulante nommée Codage vous permettant de choisir l’encodage désiré, sachant que le choix proposé par défaut est 
celui du fichier que vous avez ouvert. 

Visual  Studio  Code  affiche  également  dans  la  barre  de  statut  (celle  du  bas)  le  format  d’encodage  du  fichier 
courant. 

b. Redirection du flux standard

Création de fichiers 

Nous  avons  vu  dans  le  chapitre  concernant  les  opérateurs  qu’il  existait  un  opérateur  de  redirection,  l’opérateur 
supérieur à >. Cet opérateur représente la forme la plus simple pour créer un fichier. Il fonctionne à l’identique que 
sous  CMD.exe  (à  l’exception  près  du  type  d’encodage  par  défaut  qui  est  Unicode).  À  savoir  que  lorsqu’il  est 
utilisé de façon classique, seul le flux de sortie standard est redirigé dans un fichier. 

Exemple 

PS > Get-ChildItem C:\Temp > dir.txt

Cette  ligne  de  commandes  liste  les  fichiers  et  dossiers  contenus  dans  le  répertoire  C:\Temp  dans  le  fichier 
dir.txt. 

Pas de changement donc pour les habitués du CMD.exe, pour le fonctionnement de cet opérateur. 

Ajout de données à un fichier 

Pas de changement non plus pour l’ajout de données, qui se réalise toujours avec l’opérateur de redirection >>. 
Ainsi, grâce à cet opérateur, nous pouvons ajouter du contenu à la fin d’un fichier existant. 

Exemple 

PS > Get-Date >> dir.txt

Cette  ligne  de  commandes  aura  pour  effet  d’ajouter la date courante à la fin du fichier  dir.txt,  et  ce  tout  en 
préservant le contenu présent à l’intérieur du fichier. 

Les opérateurs de redirection de flux >  et >> font en réalité appel à la commandelette Out-File. Pour en avoir 
le  cœur  net,  appelons  à  la  rescousse  Trace-Command  (que  nous  détaillerons  dans  un  prochain  chapitre)  pour 
tenter de découvrir ce qu’il y a à l’intérieur de la bête...  

Essayons ceci : 

PS > Trace-Command -Name CommandDiscovery


-Expression {’ab’ > test.txt} -PSHost

DEBUG : CommandDiscovery Information: 0 : Looking up command: out-file


DEBUG : CommandDiscovery Information: 0 : Cmdlet found: Out-File
...

Nous voyons apparaître sur la dernière ligne Cmdlet found: Out-File, CQFD ! Mais nous pouvons encore 


faire  mieux  en  regardant  quelles  sont  les  valeurs  que  PowerShell  affecte  aux  différents  paramètres  de  Out-
File.  

c. Création de fichiers binaires avec Set­Content

Contrairement à  Out-File, cette commande écrit les données telles qu’elle les reçoit. La grande force de  Set-


Content est de pouvoir écrire directement des octets dans un fichier, et ce quel que soit le type de fichier (texte 
ou binaire). Mais attention,  Set-Content écrase le contenu du fichier de destination car elle ne possède pas de 
commutateur -Append comme Out-File. 

Il ne faut pas oublier que Set-Content fait partie de la famille des commandelettes *-Content, qui contient : 

l Add-Content : ajoute des données à un fichier existant. 
l Clear-Content : efface les données présentes dans un fichier, mais pas le fichier. 
l Get-Content : lit le contenu d’un fichier. Nous étudierons cette commandelette en détail un peu plus loin. 

Voici les paramètres de Set-Content : 

Paramètre  Description 

-Path <String[]>  Fichier de destination recevant les données. 

-Value <Object[]>  Données à écrire. 

-Include <String[]>  Modifie uniquement les éléments spécifiés. 

-Exclude <String[]>  Omet les éléments spécifiés. 

-Filter <String>  Spécifie  un  filtre  dans  le  format  ou  le  langage  du 
fournisseur. 

-PassThru <Switch>  Transmet  l’objet  traité  par  cette  commande  au  pipeline 
après l’exécution. 

-Force <Switch>  Force la commande à réussir sans compromettre la sécurité, 


par  exemple  en  créant  le  répertoire  de  destination  s’il 
n’existe pas. 

-Credential <PSCredential>  Utilise  des  informations  d’identification  pour  valider  l’accès 


au fichier. 

-Encoding <String>  Type  d’encodage  (valeur  par  défaut  :  default,  soit 


ANSI). 

Les valeurs possibles pour le paramètre d’encodage -Encoding sont les suivantes : 

Nom  Description 

ASCII  Force l’encodage en  ASCII de base (jeu de caractères 0 à 127, 7 bits). 

UTF7  Force l’encodage en Unicode  UTF7. 

UTF8BOM*  Idem  UTF8. 

UTF8NoBOM*  Force l’encodage en Unicode  UTF8 sans BOM. 

UTF8  Force l’encodage en Unicode  UTF8. 

Unicode  Force l’encodage en Unicode  UTF16 LittleEndian. 


BigEndianUnicode  Force l’encodage en Unicode  UTF16 BigEndian. 
Byte**  Force l’encodage en octet. 
String  Utilise le codage de la page de codes  ANSI actuelle du système. 

Unknown  Idem  Unicode. 

L’astérisque signifie que cette valeur n’est présente qu’avec PowerShell Core. 

Deux astérisques signifient que cette valeur n’est pas disponible avec PowerShell Core. 

IMPORTANT :  faites  bien  attention  car  les  valeurs  de  ce  paramètre  ne  sont  pas  tout  à  fait  les  mêmes  que  pour  la 
commande Out-File. 

Bien qu’il soit quand même possible d’écrire des données textuelles avec Set-Content, le plus intéressant est la 
possibilité d’écrire directement des octets dans un fichier quel que soit son type. 

Si  vous  envoyez  des  données  de  type  String  dans  un  fichier  sans  spécifier  explicitement  l’encodage  désiré,  le 
fichier  résultant  sera  un  fichier  ANSI.  C’est­à­dire  un  fichier  ASCII  étendu  avec  votre  page  de  code  courante 
pour prendre en compte les caractères accentués. 

Exemple 

Envoi de données textuelles dans un fichier. 

PS > ’AAéBB’ | Set-Content -Path ./test.txt

Cette ligne de commandes crée le fichier  test.txt au format  ANSI. À présent, regardons quelle est la taille de 


ce fichier : 

PS > Get-Item -path ./test.txt

Directory : C:\Temp

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 20/01/2015 12:15 7 test.txt

Pourquoi diable avons­nous un fichier de 7 octets alors que nous n’avons envoyé que cinq caractères à l’intérieur ? 

Appelons Format-Hex à la rescousse afin de prendre connaissance avec exactitude du contenu de notre fichier. 

PS > Format-Hex -Path ./test.txt


Path: C:\Users\Administrator\test.txt
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 41 41 E9 42 42 0D 0A AAéBB..

41, 42, et E9 sont respectivement les codes  ASCII en notation hexadécimale des caractères  A, B, et  é ; jusque­


là tout est normal. Seulement voilà, nous pouvons constater que nous avons deux octets supplémentaires en fin 
de  fichier  (matérialisés  par  des  points)  qui  sont  venus  se  rajouter  automatiquement.  Ces  octets  0D  et  0A  en 
hexadécimal ou  13, 10 en décimal correspondent aux caractères CR (Carriage Return) et LF (Line Feed). Autrement 
dit, un retour chariot et un retour à la ligne. 

Ceci est tout à fait normal car sur la plate­forme Windows (c’était déjà le cas sous DOS), chaque ligne d’un fichier 
texte se termine toujours par CR et LF. Alors que sous Unix (et autres dérivés) une ligne se termine uniquement 
par LF. C’est ce qui explique pourquoi il y a quelques problèmes de mise en forme lorsque l’on échange des fichiers 
texte entre ces plates­formes... 

Écriture d’une suite d’octets « bruts » dans un fichier 

Dans l’exemple qui va suivre, nous allons tenter d’écrire une chaîne de caractères dans un fichier mais cette fois­ci 
nous ferons en sorte que les caractères de contrôle CR et LF ne soient pas ajoutés en fin de ligne. Pour ce faire, 
nous  enverrons  les  octets  correspondants  aux  codes  ASCII  de  la  chaîne  à  écrire  ;  puis  nous  spécifierons 
l’encodage byte pour Set-Content. 

Exemple 

Écriture d’un flux d’octets dans un fichier sans CR LF. 

PS > [byte[]][char[]]’AAéBB’ | Set-Content test.txt -Encoding byte

En  faisant  cela,  nous  convertissons  la  chaîne  AAéBB  en  un  tableau  de  caractères,  que  nous  convertissons  une 
seconde fois en un tableau d’octets. Nous passons ensuite le tout à  Set-Content où nous prenons bien soin 
d’ajouter le paramètre -Encoding byte. 

Conversion de fichiers Unix en fichiers Windows (Unix2DOS) 

Dans le dernier exemple qui va suivre, nous allons créer un petit convertisseur de fichiers texte au format Unix en 
format DOS/Windows. 

Exemple 

Convertir un fichier texte Unix en DOS. 

# Convert-Unix2Dos.ps1
[CmdletBinding()]
Param (
[parameter(Mandatory=$true)]
[string]$path,
[parameter(Mandatory=$false)]
[string]$destination = $path
)

$tab = Get-Content $path -Encoding byte


for ($i=0;$i -lt $tab.length; $i++) {
if ($tab[$i] -eq 10) {
$tab = $tab[0..$($i-1)] + [byte]13 + $tab[$i..$tab.length]
$i++
}
}
$tab | Set-Content -Path $destination -Encoding Byte
Ce petit script insère le caractère de contrôle CR (13 décimal) devant chaque caractère LF (10 décimal). Ainsi, 

la suite d’octets suivante : 68 74 57 98 102 10 65 66 48 10 125 139 78 

sera transformée en : 68 74 57 98 102 13 10 65 66 48 13 10 125 139 78 

On stocke le contenu du fichier source sous forme d’une suite d’octets dans le tableau  $tab. Après, on parcourt 
l’intégralité  du  tableau  $tab à la recherche du caractère  LF. Lorsqu’on en trouve un, on concatène le début de 
notre tableau avec CR et la fin de notre tableau, puis on réinjecte le nouveau contenu dans notre tableau  $tab. 
En  somme,  nous  écrasons  à  chaque  itération  le  contenu  de $tab  par  un  nouveau  contenu  modifié.  Nous  faisons 
ceci car il n’existe pas de méthode pour insérer un élément dans un tableau à un emplacement donné. Enfin, nous 
incrémentons notre variable d’indice d’une position car nous avons ajouté un élément dans  $tab ; sans quoi le 
test serait toujours vrai et nous tomberions dans une boucle infinie. Enfin, pour l’écrire, notre tableau d’octets est 
passé via le pipeline à Set-Content sans oublier de spécifier le type d’encodage byte. 

5. Lecture de données avec Get­Content

Comme vous vous en doutez et comme son nom l’indique Get-Content va nous permettre de lire le contenu d’un 
fichier. Ce dernier peut être soit de type texte, soit de type binaire, peu importe. Get-Content s’en accommode à 
partir du moment où on lui précise l’encodage correspondant. Par défaut cette commande s’attend à lire des fichiers 
texte. 

Voici les paramètres de Get-Content : 

Paramètre  Description 

-Path <String[]>  Fichier source contenant les données à lire.  

-TotalCount <Int64>  Nombre de lignes à lire à partir du début du fichier. Par défaut 


toutes les lignes sont lues (valeur  -1). 
Alias :  First,  Head 

-Tail <Int32>  Nombre de lignes à lire à partir de la fin du fichier. 


Alias :  Last 

-ReadCount <Int64>  Nombre  de  lignes  de  contenu  envoyées  simultanément  au 
pipeline.  Par  défaut  elles  sont  envoyées  une  par  une  (valeur 
1).  Une  valeur  de  0  indique  qu’on  veut  envoyer  toutes  les 
lignes d’un coup. 

-Delimiter <String>  Spécifie le délimiteur à utiliser pour diviser le fichier en objets 


durant  la  lecture.  Par  défaut,  le  caractère  d’échappement `n 
est utilisé. 

-Raw <Switch>  Ignore  le  délimiteur  standard  et  retourne  le  fichier  d’un  seul 
bloc  (en  un  objet  unique)  au  lieu  de  retourner  un  tableau  de 
chaînes de caractères. 

-Stream <String>  Récupère  le  contenu  de  l’Alternate Data Stream  spécifié  (ne 


s’applique  que  sur  le  format  de  fichiers  NTFS).  Pour  en  savoir 
plus, rendez­vous au chapitre Sécurité. 

-Wait <Switch>  Récupère  les  nouvelles  lignes  de  texte  ajoutées  au  fichier 
(vérifie  chaque  seconde)  et  attend  indéfiniment  jusqu’à  ce 
que l’utilisateur presse [Ctrl] C. 

-Include <String[]>  Récupère uniquement les éléments spécifiés. 

-Exclude <String[]>  Omet les éléments spécifiés. 

-Filter <String>  Spécifie un filtre dans le format ou le langage du fournisseur. 


-Force <Switch>  Force la commande à réussir sans compromettre la sécurité. 

-Credential <PSCredential>  Utilise  des  informations  d’authentification  pour  valider  l’accès 


au fichier. 

-Encoding <String>  Spécifie le type d’encodage du fichier. 

Les valeurs possibles pour le paramètre d’encodage sont les suivantes : 

Nom  Description 

ASCII  Force l’encodage  en  ASCII  de  base  (jeu  de  caractères  0  à  127,  7  bits).  Les 
caractères accentués ne font pas partie du jeu de caractères. 

UTF7  Force l’encodage en Unicode  UTF7. 

UTF8  Force l’encodage en Unicode  UTF8. 

UTF8BOM*  Idem  UTF8. 

UTF8NoBOM*  Force l’encodage en Unicode  UTF8 sans BOM. 

Unicode  Force l’encodage en Unicode  UTF16 LittleEndian. 


BigEndianUnicode  Force l’encodage en Unicode  UTF16 BigEndian. 
Byte**  Force l’encodage en octet.  

String  Utilise le codage de la page de codes  ANSI actuelle du système. 

Unknown  Idem  Unicode. 

L’astérisque signifie que cette valeur n’est présente qu’avec PowerShell Core. 

Deux astérisques signifient que cette valeur n’est pas disponible avec PowerShell Core. 

Exemple 

Fonctionnalités de base. 

PS > Get-Date > ./mesProcess.txt


PS > Get-Process >> ./mesProcess.txt

PS > Get-Content ./mesProcess.txt -Totalcount 10

lundi 5 janvier 2015 21:38:09

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
46 7 1868 8152 60 0,45 2072 conhost
156 10 1236 3468 46 0,23 328 csrss
137 11 1400 14840 54 0,84 388 csrss

Dans  cet  exemple,  nous  créons  un  fichier  texte  avec  l’opérateur  de  redirection  «  supérieur  à  » (Unicode,  donc) 
contenant la date, l’heure  ainsi  que  la  liste  des  processus  en  cours  d’exécution.  Puis,  nous  faisons  appel  à  Get-
Content pour lire les dix premières lignes du fichier. 
Manipuler un fichier comme un tableau 

Lorsque l’on utilise Get-Content, nous obtenons en retour un tableau de chaînes de caractères. Comme il s’agit 
d’un tableau, il devient alors très facile de manipuler son contenu ou d’aller lire une ligne spécifique. 

Exemple : lecture de la 15e ligne d’un fichier 

PS > $fic = Get-Content FableLaFontaine.txt


PS > $fic[14]
La fourmi n’est pas prêteuse ;

Nous  recevons  le  contenu  du  fichier  dans  la  variable  $fic,  puis  nous  récupérons  la  ligne  située  à  l’indice  14  du 
tableau (en réalité la 15 e  ligne du fichier car n’oubliez pas que les indices de tableau commencent à zéro).  

De  plus,  comme  une  chaîne  est  également  un  tableau  de  caractères,  on  peut  lire  n’importe  quel  caractère  en 
utilisant la syntaxe des tableaux à deux dimensions. Par exemple, le i du mot fourmi se trouvant à l’index 8 : 

PS > $fic[14][8]
i

Enfin pour terminer cet exemple, si nous demandons la propriété  Length à notre tableau  $fic, nous obtiendrons 


le nombre d’éléments qui le composent, soit le nombre total de lignes de notre fichier texte. 

PS > $fic.Length
22

22 est le nombre de lignes de notre fichier. 

Lecture d’un fichier en mode « brut » 

Comme  nous  vous  le  disions  en  introduction  de  cette  commande,  Get-Content  sait  lire  des  octets.  Cette 
fonctionnalité est particulièrement intéressante pour révéler le contenu réel des fichiers, c’est en quelque sorte un 
mode d’accès de bas niveau au contenu. 

En  effet,  qu’est­ce  qui  différencie  un  fichier  texte  d’un  fichier  binaire  ?  La  réponse  est  simplement  :  le  contenu  ou 
l’interprétation de celui­ci. Dans les deux cas, un fichier possède des attributs qui caractérisent tels qu’un nom, une 
extension, une taille, une date de création, etc. 

Un  fichier  texte  contient,  tout  comme  son  homologue  le  fichier  binaire,  une  suite  d’octets  possédant  une  certaine 
structure. 

Essayons d’ouvrir en mode brut un fichier texte Unicode, mais auparavant créons un nouveau fichier : 

PS > ’PowerShell’ | Out-File .\test.txt -Encoding unicode


PS > Get-Content .\test.txt -Encoding byte

255 254 80 0 111 0 119 0 101 0 114 0 83 0 104 0 101 0 108 0 108 0 13 0 10 0
Les  octets  s’affichent  en  réalité  verticalement,  mais  pour  faciliter  la  lecture  et  la  compréhension  de  l’exemple  nous 
les avons retranscrits horizontalement. 

Afin d’afficher le résultat sur une seule ligne, nous aurions pu écrire ceci : 

PS > (Get-Content .\test.txt -Encoding byte) -join ’ ’

Dans ce contexte, l’opérateur -join réalise une concaténation des éléments du tableau avec le 
caractère espace. 

Un œ il averti avec les fichiers texte remarquerait les deux choses suivantes : 

l Le fichier débute par deux octets remarquables : 255 et 254. 

l Tous les caractères sont codés sur deux octets dont l’un des deux vaut zéro. 

Vous remarquerez également la présence des octets  13 et  10 en fin de ligne correspondant à CR et LF (voir plus 


haut dans ce chapitre). 

La  présence  des  octets  255  et  254  s’explique  par  le  fait  que  tout  fichier  Unicode  commence par  un  en­tête (le 
BOM dont nous avons parlé au début de ce présent chapitre) dont la longueur varie entre 2 et 4 octets. Cela diffère 
selon le codage Unicode choisi (UTF8, UTF16, UTF32). 

Dans  le  cas  présent,  255


254  (FF FE  en  notation  hexadécimale)  signifie  que  nous  avons  affaire  à  un  fichier 
encodé en UTF16 Little Endian. 

La  présence  des  zéros  s’explique  par  le  fait  que  dans  un  fichier  UFT16  tous  les  caractères  sont  codés sur  deux 
octets. 

Exemple : Déterminer le type d’encodage d’un fichier 

La  question  que  nous  nous  posions  déjà  depuis  quelques  pages,  à  savoir  :  «  comment  reconnaître  le  type 
d’encodage  d’un  fichier  texte  ? »  a,  enfin  trouvé  sa  réponse  dans  l’exemple  précédent.  Les  premiers  octets  d’un 
fichier texte nous donnent son encodage. 

Réalisons donc un petit script utilitaire qui nous dira de quel type est l’encodage d’un fichier à partir de ses premiers 
octets. 

# Get-FileTypeEncoding.ps1
[CmdletBinding()]
Param (
[parameter(Mandatory=$true)]
[string]$path
)

# définition des variables et constantes


$ANSI=0
Set-Variable -Name UTF8BOM -Value ’EFBBBF’ -Option constant
Set-Variable -Name UTF16LE -Value ’FFFE’ -Option constant
Set-Variable -Name UTF16BE -Value ’FEFF’ -Option constant
Set-Variable -Name UTF32LE -Value ’FFFE0000’ -Option constant
Set-Variable -Name UTF32BE -Value ’0000FEFF’ -Option constant

$fic = Get-Content -Path $path -Encoding byte -First 4


# Mise en forme des octets lus sur 2 car. et conversion en Hexa
# ex : 0 -> 00, ou 10 -> 0A au lieu de A
# et concaténation des octets dans une chaîne pour effectuer la
# comparaison
[string]$strLue = [string](’{0:x}’ -f $fic[0]).PadLeft(2, ’0’) +
[string](’{0:x}’ -f $fic[1]).PadLeft(2, ’0’) +
[string](’{0:x}’ -f $fic[2]).PadLeft(2, ’0’) +
[string](’{0:x}’ -f $fic[3]).PadLeft(2, ’0’)
Switch -regex ($strLue){
"ˆ$UTF32LE" {’Unicode UTF32LE’; break}
"ˆ$UTF32BE" {’Unicode UTF32BE’; break}
"ˆ$UTF8BOM" {’Unicode UTF8 with BOM’; break}
"ˆ$UTF16LE" {’Unicode UTF16LE’; break}
"ˆ$UTF16BE" {’Unicode UTF16BE’; break}
default # le fichier n’est pas encodé en Unicode,
{ # on approfondit l’examen du fichier...
# Recherche d’un octet dont la valeur est > 127
$fic = Get-Content -Path $path -Encoding byte
if ($fic -gt 127) {
’ANSI’
}
else {
’ASCII’
}
} #fin default
} #fin switch

Ce script lit les quatre premiers octets du fichier, les met en forme (conversion hexadécimale au format texte) et les 
compare  à  la  signature  Unicode  pour  déterminer  le  type  d’encodage.  Si  aucune  signature  n’a été trouvée, c’est 
que le fichier est soit de type ASCII pur (caractères US de 0 à 127), soit de type ANSI (ASCII étendu, soit ANSI 
+ page de codes pour gérer les caractères accentués). 

Cet exemple n’est pas parfait car il ne prend pas en compte les fichiers encodés en UTF­8 sans BOM. Pour ce faire, il 
aurait fallu ajouter une vérification complémentaire, sorte d’analyse heuristique du contenu, car pas de BOM signifie 
pas d’en­tête. Il est donc plus difficile de déterminer avec certitude le format d’encodage d’un fichier.  

Le  format  UTF8NoBOM  est  cependant  le  format  privilégié  de  PowerShell  Core,  et  ce  pour  des  raisons 
d’interopérabilité avec les autres plateformes et donc d’homogénéité de fonctionnement. 

6. Recherche de contenu dans un fichier avec Select­String

Grâce  à  Select-String  nous  pouvons  passer  en  revue  le  contenu  d’une  chaîne  de  caractères,  d’un  fichier,  ou 
d’un  grand  nombre  de  fichiers  à  la  recherche  d’une  chaîne  de  caractères  sous  forme  d’expression  régulière.  Les 
"Unixiens"  connaissant  la  commande Grep  ne  seront  pas  dépaysés  car  Select-String  se  veut  être  plus  ou 
moins son équivalent. 

Voici les paramètres de Select-String : 

Paramètre  Description 

-Pattern <String[]>  Chaîne simple ou expression régulière à rechercher. 


-Path <String[]>  Cible de la recherche : chaîne(s) ou fichier(s).  

-InputObject <PSObject>  Accepte un objet comme entrée.  

-Include <String[]>  Récupère uniquement les éléments spécifiés.  

-Exclude <String[]>  Omet les éléments spécifiés.  

-SimpleMatch <Switch>  Spécifie  qu’une  correspondance  simple,  plutôt  qu’une 


correspondance d’expression régulière, doit être utilisée.  

-CaseSensitive <Switch>  Rend les correspondances sensibles à la casse. 

-Quiet <Switch>  Remplace le résultat de la commande par une valeur booléenne.  

-List <Switch>  Spécifie  qu’une  seule  correspondance  doit  être  retournée  pour 
chaque fichier d’entrée.  

-AllMatches <Switch>  Recherche plusieurs correspondances dans chaque ligne de texte. 


Sans  ce  paramètre,  Select-String  recherche  uniquement 
la première correspondance dans chaque ligne de texte.  

-Context <Int32>  Permet  de  sélectionner  un  nombre  spécifique  de  lignes  avant  et 
après  la  ligne  contenant  la  correspondance  (permettant  ainsi  de 
voir le contenu recherché dans son contexte).  

-Encoding <String>  Indique  l’encodage  du  flux  texte  auquel  Select-String 


doit  s’appliquer.  Les  valeurs  peuvent  être  : 
UTF7,  UTF8, 
UTF32,  Ascii,  Unicode,  BigEndianUnicode, 
Default ou  OEM. 
-NotMatch <Switch>  Indique quel modèle la recherche ne retourne pas. Ce paramètre 
est  très  utile  pour  réaliser  une  recherche  inversée  (en  ne 
sélectionnant  pas  les  lignes  basées  sur  le  modèle).  Équivalent  à 
Grep -v. 

Les  caractères  accentués  ne  sont  pas  pris  correctement  en  compte  dans  les  recherches à  l’intérieur  des  fichiers 
ANSI. Par contre, tout fonctionne correctement avec les fichiers Unicode. 

Exemple 

Recherche simple. 

PS > Select-String -Path C:\Temp\*.txt -Pattern ’fourmi’

C:\Temp\CigaleFourmi.txt:8:Chez la fourmi sa voisine,


C:\Temp\CigaleFourmi.txt:15:La fourmi n’est pas prêteuse ;
C:\Temp\FourmisUtiles.txt:1:Les fourmis sont très utiles.

Dans cet exemple, nous recherchons la chaîne « fourmi » parmi tous les fichiers texte du répertoire C:\Temp. 

Nous obtenons en retour le nom des fichiers (ou du fichier s’il n’y en avait eu qu’un seul) qui contiennent la chaîne 
recherchée.  Les  valeurs  8,  15  et  1  correspondent  au  numéro de  la  ligne  dans  le  fichier  où  une  occurrence  a  été 
trouvée. 

Parfois, lorsque les résultats sont nombreux, il est intéressant d’utiliser  le  commutateur  -List pour spécifier à la 


commandelette de ne retourner que le premier résultat trouvé par fichier. 

Regardons quel serait le résultat avec -List : 
PS > Select-String -Path C:\Temp\*.txt -Pattern ’fourmi’ -List

C:\Temp\CigaleFourmi.txt:8:Chez la fourmi sa voisine,


C:\Temp\FourmisUtiles.txt:1:Les fourmis sont très utiles.

Les  résultats  obtenus  sont  de  type  Microsoft.PowerShell.Commands. MatchInfo.  Ainsi,  il  est  possible 
d’obtenir  et  de  manipuler  un  certain  nombre  d’informations  complémentaires  en  passant  par  une  variable 
intermédiaire, comme ceci : 

PS > $var = Select-String -Path C:\Temp\*.txt -Pattern ’fourmi’


PS > $var | Get-Member -Membertype property

TypeName: Microsoft.PowerShell.Commands.MatchInfo

Name MemberType Definition


---- ---------- ----------
Context Property Microsoft.PowerShell.Commands.MatchInfoContext ...
Filename Property System.String Filename {get;}
IgnoreCase Property System.Boolean IgnoreCase {get;set;}
Line Property System.String Line {get;set;}
LineNumber Property System.Int32 LineNumber {get;set;}
Matches Property System.Text.RegularExpressions.Match[] Matches ...
Path Property System.String Path {get;set;}
Pattern Property System.String Pattern {get;set;}

À présent, essayons de forcer un affichage sous forme de liste : 

PS > $var | Format-List

IgnoreCase : True
LineNumber : 8
Line : Chez la fourmi sa voisine,
Filename : CigaleFourmi.txt
Path : C:\Temp\CigaleFourmi.txt
Pattern : fourmi
Context :
Matches : {Fourmi}

IgnoreCase : True
LineNumber : 15
Line : La fourmi n’est pas prêteuse ;
Filename : CigaleFourmi.txt
Path : C:\Temp\CigaleFourmi.txt
Pattern : fourmi
Context :
Matches : {Fourmi}

IgnoreCase : True
LineNumber : 1
Line : Les fourmis sont très utiles.
Filename : fourmisUtiles.txt
Path : C:\Temp\FourmisUtiles.txt
Pattern : fourmi
Context :
Matches : {Fourmi}

Ainsi nous pouvons demander le numéro de ligne de la première occurrence : 

PS > $Var[0].Linenumber
8

Exemple 

Autre recherche simple. 

Nous pouvons également utiliser Select-String en lui passant les données cibles au travers du pipeline comme cela : 

PS > Get-Item C:\Temp\*.txt | Select-String -Pattern ’fourmi’

Les résultats obtenus seront les mêmes que dans l’exemple précédent. 

Ne  vous  trompez  pas  !  Utilisez  bien  Get-Item  ou  Get-ChildItem  et  non  pas  Get-Content  car  bien  que 
cela  semble  fonctionner,  le  résultat  n’est  généralement  pas  celui  attendu.  En  effet,  vous  passeriez  au  pipeline  le 
contenu des fichiers et non pas les fichiers eux­mêmes, et le contenu est en quelque sorte concaténé. Ce qui aurait pour 
conséquence de fausser la valeur de la propriété LineNumber. 

Exemple 

PS > $var = Get-Content C:\Temp\*.txt | Select-String -Pattern ’fourmi’


PS > $var | Format-List

IgnoreCase : True
LineNumber : 8
Line : Chez la fourmi sa voisine,
Filename : InputStream
Path : InputStream
Pattern : fourmi
Context :
Matches : {Fourmi}

IgnoreCase : True
LineNumber : 15
Line : La fourmi n’est pas prêteuse ;
Filename : InputStream
Path : InputStream
Pattern : fourmi
Context :
Matches : {Fourmi}
IgnoreCase : True
LineNumber : 23
Line : Les fourmis sont très utiles.
Filename : InputStream
Path : InputStream
Pattern : fourmi
Context :
Matches : {Fourmi}

Dans cet exemple, on notera que : 

l Le  nom  de  fichier  a  disparu  des  résultats  pour  être  remplacé  par  un  «  InputStream  »  qui  indique  la  provenance  des 
données. 

l Tout  lien  avec  le  fichier  d’origine  ayant  disparu,  le  numéro  de  ligne  est  relatif  à  l’ensemble  du  flux,  ce  qui  donne  un 
résultat  potentiellement  erroné  si  l’on  s’attend  à  avoir  la  position  dans  le  fichier  (voir  la  troisième  et  dernière 
occurrence ci­dessus). 

Exemple 3 

Recherche à base d’expression régulière. 

PS > Get-item $pshome/en-US/*.txt | Select-String -Pattern ’World$’

C:\...\about_Preference_Variables.help.txt:293: DEBUG: Hello, World


C:\...\about_Preference_Variables.help.txt:313: DEBUG: Hello, World
C:\...\about_Preference_Variables.help.txt:403: ...:continue:Hello,World

...

Cette  ligne  de  commandes  explore  tous  les  fichiers  dont  l’extension  est .txt  à  la  recherche d’une  chaîne  se 
terminant par World. 

L’exemple  précédent  repose  sur  une  expression  régulière.  Pour  que  Select-String  fasse  une  recherche  sur 
une  expression  littérale  plutôt  que  sur  une  expression  régulière,  il  faut  employer  le  paramètre  -SimpleMatch. 
Ce commutateur est nécessaire lorsque la chaîne de recherche contient des caractères spéciaux qui ont une signification 
dans le langage des expressions régulières, tels que le dollar, le point, l’étoile, etc. 

Exemple 

Recherche dont le résultat est un booléen. 

PS > Select-String CigaleFourmi.txt -Pattern ’fourmi’ -Quiet


True

PS > Select-String CigaleFourmi.txt -Pattern ’elephant’ -Quiet


False

Exemple 

Recherche d’une chaîne en affichant son contexte (2 lignes avant et 2 lignes après). 
PS > Select-String Cigalefourmi.txt -Pattern ’Août’ -Context 2

Cigalefourmi.txt:11:Jusqu’à la saison nouvelle


Cigalefourmi.txt:12:"Je vous paierai, lui dit-elle,
Cigalefourmi.txt:13:Avant l’août, foi d’animal,
Cigalefourmi.txt:14:Intérêt et principal."
Cigalefourmi.txt:15:La fourmi n’est pas prêteuse ;

Nous aurions pu ajouter le commutateur -SimpleMatch afin de préciser que notre recherche porte sur une chaîne 
littérale  et  non  pas  sur  une  expression  régulière.  Cela  fonctionne  correctement  car  il  n’y  a  pas  de  caractères 
spéciaux dans notre chaîne de recherche.  

7. Gestion des fichiers CSV

a. Import/export de données

Les  fichiers  CSV  (Comma­Separated  Values)  sont  des  fichiers  texte  dont  les  valeurs  sont  séparées  par  un 
séparateur.  Généralement,  la  première  ligne  de  ces  fichiers  est  l’en­tête.  Celui­ci  comprend  le  nom  de  chaque 
« colonne » de données ou « champ ». Le nom des champs ainsi que les valeurs sont séparés par un séparateur 
qui est la virgule dans le milieu anglo­saxon, et le point­virgule dans le milieu francophone. 

Voici un exemple de fichier CSV très simple : 

Sexe;Prenom;Annee_de_naissance
F;Géraldine;1978
M;Stan;2008
F;Eléonore;2004

PowerShell comprend un jeu de deux commandes pour gérer ces fichiers : Export-CSV pour créer un fichier CSV, 
Import-CSV pour lire un fichier CSV. 

Voici les différents paramètres de Export-CSV : 

Paramètre  Description 

-Path <String>  Chemin du fichier de destination. 

-Append <Switch>  Écrit des valeurs à la suite d’un fichier existant. 

-InputObject <PSObject>  Accepte un objet comme entrée. 

-Force <Switch>  Remplace le fichier spécifié si la destination est déjà existante. 

-Encoding <String>  Type d’encodage  du  fichier  à  créer  (cf.  Out-File  pour  la  liste 
des  valeurs  possibles). ASCII  est  le  type  par  défaut  avec 
Windows PowerShell. 

-NoTypeInformation <Switch>  Par  défaut,  une  ligne  contenant  le  type  des  données 
(commençant  par  #TYPE)  est  écrite  avant  l’en­tête.  Si  ce 
commutateur est spécifié, cette ligne ne sera pas écrite.  

-NoClobber <Switch>  Ne pas écraser le fichier s’il existe déjà.  

-Delimiter <Char>  Très  utile,  ce  paramètre  permet  de  spécifier  un  caractère 
délimiteur  pour  séparer  les  valeurs  de  propriété.  La  valeur  par 
défaut est la virgule. 

-UseCulture <Switch>  En  lieu  et  place  du  paramètre 


-Delimiter,  vous  pouvez 
également  utiliser  -UseCulture.  En  spécifiant  une  culture 
spécifique,  PowerShell  adaptera  le  délimiteur  (le  délimiteur  pour 
la  culture  fr­FR  est  le  point­virgule).  Pour  le  vérifier,  essayez : 
(Get-Culture).TextInfo.ListSeparator. 

Et voici ceux de Import-CSV : 

Paramètre  Description 

-Path <String[]>  Chemin du fichier source.  

-Delimiter <Char>  Très  utile,  ce  paramètre  permet  de  spécifier  un  caractère  délimiteur  pour 
séparer les valeurs de propriété. La valeur par défaut est une virgule. 

-UseCulture <Switch>  En  lieu  et  place  du  paramètre  -Delimiter,  vous  pouvez  également 
utiliser  -UseCulture.  En  spécifiant  une  culture  spécifique,  PowerShell 
adaptera  le  délimiteur  (le  délimiteur  pour  la  culture  fr­FR  est  le  point­
virgule).  Pour  le  vérifier,  essayez :  (Get-
Culture).TextInfo.ListSeparator. 
-Header <String[]>  Permet  de  spécifier  une  autre  ligne  d’en­tête  que  celle  contenue  dans  le 
fichier  importé.  Permet  aussi  de  spécifier  un  en­tête  aux  fichiers  CSV  qui 
n’en n’auraient pas. 

Exemple : Export-CSV 

PS > Get-Eventlog Application -Newest 5 |


Select-Object TimeGenerated, EntryType, Source, EventID |
Export-CSV C:\Temp\EventLog.csv -Encoding Unicode

PS > Get-Content C:\Temp\EventLog.csv

#TYPE Selected.System.Diagnostics.EventLogEntry
"TimeGenerated","EntryType","Source","EventID"
"05/01/2015 20:46:26","Information","Windows Reporting","1001"
"05/01/2015 20:44:48","Information","ESENT","327"
"05/01/2015 20:44:48","Information","ESENT","326"
"05/01/2015 20:41:04","Information","Wlclntfy","6000"
"05/01/2015 20:41:02","Information","Wlclntfy","6003"

Nous venons de créer un fichier texte  Unicode nommé  EventLog.csv. Comme nous n’avons pas spécifié de 


délimiteur,  la  virgule  a  été  utilisée  (valeur  par  défaut).  Le  fichier  contient  les  propriétés 
TimeGenerated, 
Entrytype,  Source,  EventID d’un  objet  de  type  journal  Application.  Veuillez  noter  que  la  première  ligne  du 
fichier  commence  par  #TYPE suivi du type de l’objet  contenu  dans  notre  fichier  ;  autrement  dit,  il  s’agit  du  type 
généré par la commande Get-EventLog. 

Faites attention, car par défaut Export-CSV génère des fichiers de type ASCII, autrement dit sans caractères 
accentués. Il est donc important de ne pas oublier le type d’encodage souhaité lorsque l’on travaille en français. 

Exemple 1 : Import-CSV 

PS > $journal = Import-Csv C:\Temp\EventLog.csv


PS > $journal

TimeGenerated EntryType Source EventID


------------- --------- ------ -------
05/01/2015 20:46:26 Information Windows Re... 1001
05/01/2015 20:44:48 Information ESENT 327
05/01/2015 20:44:48 Information ESENT 326
05/01/2015 20:41:04 Information Wlclntfy 6000
05/01/2015 20:41:02 Information Wlclntfy 6003

À présent, observons les propriétés et méthodes de l’objet contenu dans $journal : 

PS > $journal | Get-Member

TypeName: CSV:Selected.System.Diagnostics.EventLogEntry

Name MemberType Definition


---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
EntryType NoteProperty System.String EntryType=Information
EventID NoteProperty System.String EventID=1001
Source NoteProperty System.String Source=Windows Reporting
TimeGenerated NoteProperty System.String TimeGenerated=05/01/2018 20:46:26

Nous  pouvons  nous  apercevoir  que  nous  avons  des  propriétés  qui  correspondent  au  nom  de  notre  ligne  d’en­
tête ; ce qui va être fort utile pour en récupérer les valeurs ! Par exemple : 

PS > $journal[0].EventID
1001

Exemple 2 : Export-CSV et Import-CSV 

Imaginons  à  présent  que  nous  soyons  confrontés  à  la  recherche  de  résultats  dans  un  fichier  CSV  puis  à  leurs 
modifications. Prenons comme exemple le fichier suivant : 

Nom;Prenom;Domaine;Derniere_Connexion
Lemesle;Robin;powershell-scripting.com;20/03/2018
Petitjean;Arnaud;powershell-scripting.com;19/09/2017
Teixeira;Jessica;;02/02/2018

Dans  ce  fichier,  trois  personnes  sont  identifiées.  Parmi  elles,  l’une  n’est  pas  identifiée  comme  appartenant  au 
domaine powershell­scripting.com, et nous nous devons de corriger cette anomalie. 

Dans un premier temps, importons le fichier. 
PS > $utilisateurs = Import-Csv ./utilisateurs.csv -UseCulture
PS > $utilisateurs

Nom Prenom Domaine Derniere_Connexion


--- ------ ------- ------------------
Lemesle Robin powershell-scripting.com 20/03/2018
Petitjean Arnaud powershell-scripting.com 19/09/2017
Teixeira Jessica 02/02/2018

PS > $utilisateurs[0]

Nom Prenom Domaine Derniere_Connexion


--- ------ ------- ------------------
Lemesle Robin powershell-scripting.com 20/03/2018

Comme on peut le voir ci­dessus, la variable  $utilisateurs se comporte comme un tableau (c’est normal car 


c’en est un) dans lequel chaque ligne correspond à un numéro d’index. De plus chaque objet défini dans le tableau 
dispose  des  propriétés  Nom,  Prenom,  Domaine,  Derniere_Connexion,  correspondant  aux  noms  des 
colonnes de notre fichier CSV. 

PS > $utilisateurs[0].Nom
Lemesle

PS > $utilisateurs[0].Domaine
powershell-scripting.com

Bien entendu, le tableau peut être parcouru avec une boucle et chacune des valeurs est modifiable ; c’est le cas ci­
dessous.  Pour  chaque  utilisateur,  si  un  domaine  n’est  pas  spécifié  alors  on  lui  ajoute  la  valeur  PowerShell-
scripting.com. 

PS > Foreach($utilisateur in $utilisateurs){


if(($utilisateur.Domaine) -eq ’’){
$utilisateur.Domaine = ’PowerShell-scripting.com’
"l’utilisateur $($utilisateur.Nom) a été ajouté au domaine"
}
}
l’utilisateur Teixeira a été ajouté au domaine

PS > $utilisateurs

Nom Prenom Domaine Derniere_Connexion


--- ------ ------- ------------------
Lemesle Robin powershell-scripting.com 20/03/2018
Petitjean Arnaud powershell-scripting.com 19/09/2017
Teixeira Jessica PowerShell-scripting.com 02/02/2018

Enfin, pour prendre en compte les changements apportés, l’enregistrement de la variable $utilisateurs dans 
le fichier utilisateurs.csv s’effectue avec la commande Export-Csv. 

PS > $utilisateurs | Export-Csv utilisateurs.csv `


-Encoding Unicode -UseCulture

L’avantage  des  fichiers  CSV  délimités  avec  le  point­virgule,  c’est  qu’ils  sont  reconnus  nativement 
dans  Microsoft  Excel.  Ainsi  lorsque  vous  double  cliquerez  sur  le  fichier  CSV,  Excel  devrait 
automatiquement le convertir et l’afficher. 

b. Conversion de données au format CSV

Il  est  possible  grâce  à  ConvertTo-CSV  de  transformer  un  tableau  d’objets  en  un  tableau de  chaînes  de 
caractères au format CSV. ConvertTo-CSV remplit grosso modo la même fonction que Export-CSV (d’ailleurs il 
accepte  pratiquement  les  mêmes  paramètres)  sauf  que  la  conversion  est  réalisée  en  mémoire  et  non  vers  un 
fichier texte. 

Cela  apporte  de  la  flexibilité  dans  le  cas  où  nous  souhaitons  transformer  les  données  avant  de  les  écrire  sur 
disque. 

Exemple 1 : Conversion d’un objet unique 

PS > $obj = [PSCustomObject] @{


Nom = ’Arnaud Petitjean’;
Email = ’arnaud@psh.local’;
siteWeb = ’www.psh.local’;
codePostal = 33950}

PS > $obj | ConvertTo-Csv -UseCulture -NoTypeInformation

"Nom";"Email";"siteWeb";"codePostal"
"Arnaud Petitjean";"arnaud@psh.local";"www.psh.local";"33950"

Exemple 2 : Conversion d’une collection d’objets 

PS > Get-Verb | Select-Object -First 5 | ConvertTo-CSV

#TYPE Selected.System.Management.Automation.PSCustomObject
"Verb","Group"
"Add","Common"
"Clear","Common"
"Close","Common"
"Copy","Common"
"Enter","Common"

La  commandelette  Get-Verb  retourne  la  liste  des  verbes  approuvés  par  Microsoft  pour  ce  qui 
concerne  le  nommage  des  fonctions  et  en  particulier  des  fonctions  avancées  lorsqu’elles  sont 
incluses dans un module. Si une fonction exportée par un module possède un verbe non approuvé, 
alors un message d’avertissement sera affiché au chargement du module. 

c. Conversion de données à partir du format CSV

Précédemment nous avons vu comment convertir un objet en un tableau de chaînes de caractères répondant au 
format CSV, à présent nous allons faire l’opération inverse. À savoir, convertir des données répondant au format 
CSV en objets.  

Bien  que  la  démarche  puisse  paraître  curieuse  au  premier  abord,  vous  allez  vite  comprendre,  au  travers  des 
exemples à suivre, les cas d’usages intéressants de la commandelette ConvertFrom-CSV. 

Tout  d’abord  il  faut  savoir  que  ConvertFrom-CSV  fonctionne  parfaitement  de  concert  avec  sa  sœ ur  jumelle 
ConvertTo-CSV ; cependant nous n’avons pas encore trouvé d’intérêt à convertir un objet natif en CSV puis à 
faire l’opération inverse. Par contre, là où ConvertFrom-CSV prend tout son sens, c’est lorsque nous travaillons 
avec des commandes héritées du système d’exploitation qui génèrent en sortie des données au format CSV. 

Prenons  par  exemple  le  cas  d’espèce  de  la  commande  Whoami.exe.  Celle­ci  retourne  de  nombreuses 
informations  sur  l’utilisateur  connecté  :  ses  groupes  d’appartenance,  son  SID,  ainsi  que  de  nombreuses  autres 
informations. 

Essayons la commande suivante qui renvoie le SID de l’utilisateur connecté : 

PS > whoami.exe /user

USER INFORMATION
----------------
User Name SID
=================== ===========================================
adps1\administrator S-1-5-21-3471033758-2576861177-32356578-500

Le résultat de cette commande est très intéressant, mais comment récupérer la valeur du SID afin de l’exploiter 
dans  un  script ?  La  première  idée  qui  vient  en  tête  est  celle  qui  consisterait  à  analyser  le  flux  texte  pour  en 
extraire le SID. Pourquoi pas ? Ceci dit, cette démarche est parfois risquée car si un caractère ou une ligne diffère 
par rapport au résultat attendu, alors nous risquons de ne pas extraire la bonne valeur. Par conséquent l’idée est 
ici d’exploiter la possibilité de cet utilitaire à générer un résultat au format CSV. Ainsi en ajoutant l’option /FO CSV 
à la ligne de commande, nous lui demandons de fournir un flux texte au format CSV. 

Essayons à nouveau en ajoutant /FO CSV : 

PS > whoami.exe /user /FO CSV

"User Name","SID"
"adps1\administrator","S-1-5-21-3471033758-2576861177-32356578-500"

C’est  mieux.  Cela  ressemble  bien  à  un  format  CSV.  Voyons  maintenant  le  résultat  si  nous  passons  le  retour  de 
cette ligne de commandes à ConvertFrom-CSV : 

PS > whoami.exe /user /FO CSV | ConvertFrom-Csv

User Name SID


--------- ---
adps1\administrator S-1-5-21-3471033758-2576861177-32356...

Cette fois­ci le résultat est un bel objet PowerShell ayant les propriétés Nom d’utilisateur et SID. À présent 


il est aisé de récupérer le SID de l’utilisateur courant : 
PS > $user = whoami.exe /user /FO CSV | ConvertFrom-Csv
PS > $user.SID
S-1-5-21-3471033758-2576861177-32356578-500

Ceci  n’est  certainement  pas  la  meilleure  approche  pour  récupérer  le  SID  de  l’utilisateur  courant.  Cet  exemple  a 
uniquement  pour  but  d’illustrer  le  fait  qu’il  est  facile  de  convertir  un  flux  texte  au  format  CSV  venant  d’utilitaires 
tierces et de les convertir en objets PowerShell. 

Toujours  avec  l’utilitaire  Whoami.exe  il  est  possible  de  connaître  les  groupes  d’appartenance de  l’utilisateur 
courant. Voyons comment convertir le résultat de façon à en récupérer un objet PowerShell. 

PS > whoami.exe /groups /FO CSV | ConvertFrom-CSV

Group Name Type SID Attributes


---------- ---- --- ----------
Everyone Well-known group S-1-1-0 Mandatory group,...
BUILTIN\Administ... Alias S-1-5-32-544 Mandatory group,...
BUILTIN\Users Alias S-1-5-32-545 Mandatory group,...
BUILTIN\Certific... Alias S-1-5-32-574 Mandatory group,...
BUILTIN\Pre-Wind... Alias S-1-5-32-554 Mandatory group,...
...

En  résumé,  bien  que  d’apparence  anodine,  la  commande  ConvertFrom-CSV  est  très  puissante  et  peut  vous 
rendre bien des services. N’hésitez donc pas à en abuser lorsque vous en avez la possibilité car ce sera bien plus 
simple que de « parser » les résultats à l’aide d’expressions régulières complexes. 

8. Gestion des fichiers XML

XML (Extensible Markup Language) est un langage basé sur une hiérarchisation des données sous forme de balise. 
Pour savoir à quoi ressemble du XML, le mieux est certainement d’en voir un exemple. 

<Livre>
<Titre>Windows PowerShell</Titre>
<SousTitre>Les fondamentaux</SousTitre>
<Auteur>
<Nom>Arnaud Petitjean</Nom>
<AnnéeDeNaissance>1974</AnnéeDeNaissance>
<Distinction>MVP PowerShell</Distinction>
</Auteur>

<Auteur>
<Nom>Robin Lemesle
</Nom>
<AnnéeDeNaissance>1985</AnnéeDeNaissance>
<Distinction>MVP PowerShell</Distinction>
</Auteur>
<Chapitre>
<Nom>Introduction</Nom>
<NombrePage>100</NombrePage>
</Chapitre>

<Chapitre>
<Nom>A la découverte de PowerShell</Nom>
<NombrePage>120</NombrePage>
</Chapitre>

</Livre>

Pour connaître l’ensemble des commandes liées à l’utilisation de fichier XML, tapez la commande suivante : 

PS > Get-Command -Type cmdlet *XML*

CommandType Name Definition


----------- ---- ----------
Cmdlet ConvertTo-Xml ConvertTo-Xml [-InputO...
Cmdlet Export-Clixml Export-Clixml [-Path]...
Cmdlet Import-Clixml Import-Clixml [-Path]...
Cmdlet Select-Xml Select-Xml [-XPath] <S...

Commande  Description 

ConvertTo-Xml  Crée une représentation XML (en mémoire) à partir d’objets .NET. 

Export-Clixml  Exporte un ou plusieurs objet(s) en une représentation XML dans un fichier. Ce 
mécanisme est appelé « sérialisation d’objets ». 

Import-Clixml  Importe  un  fichier  XML  exclusivement  généré  par  Export-CliXML  et 
convertit  le  résultat  en  représentation  objet.  Ce  mécanisme  est  appelé 
« désérialisation d’objets ». 

Select-Xml  Permet d’effectuer  des  requêtes  de  recherche  au  format  XPath  au  sein  d’un 
document XML. 

Import-Clixml  permet  uniquement l’importation  de  fichiers  XML  générés  par  la  commande  Export-
Clixml. 

a. Chargement d’un fichier XML

Pour importer notre fichier d’exemple, il suffit de réaliser un transtypage sur un tableau de chaînes de caractères 
retourné  par  Get-Content.  Le  fichier  XML  importé  dans  l’exemple  suivant  est  celui  présenté  dans  le  fichier 
Livre.xml. 
 

PS > $Livre = [xml](Get-Content ./Livre.xml)


PS > $Livre

Livre
-----
Livre

b. Gestion du contenu

Maintenant  que  le  fichier  XML  est  importé  en  mémoire  dans  la  variable  $Livre,  il  est  alors  très  simple  de  le 
parcourir. Chaque nœ ud qui le compose est à présent représenté sous forme de propriétés.  

Exemples 

PS > $Livre.Livre

Titre SousTitre Auteur Chapitre


----- --------- ------ --------
Windows PowerShell Les... {Auteur... {Chapitre, Chapitre}

PS > $Livre.Livre.Titre

Windows PowerShell

PS > $livre.Livre.auteur

Nom AnnéeDeNaissance Distinction


--- ---------------- -----------
Arnaud Petitjean 1974 MVP PowerShell
Robin Lemesle 1985 MVP PowerShell

Des  modifications  peuvent  également  être  effectuées  en  mémoire,  pour  cela  il  suffit  d’indiquer  quelle  nouvelle 
valeur doit prendre un nœ ud en question. 

PS > $livre.Livre.Titre = ’Le livre Windows PowerShell’


PS > $Livre.Livre

Titre SousTitre Auteur Chapitre


----- --------- ------ --------
Le livre Windows PowerShell Les... {Auteur... {Chapitre...

Nous venons de voir comment explorer un fichier XML personnalisé, ce qui est très simple et pratique. 

c. Export d’objets au format XML

PowerShell  est  doté  de  la  commande  ConvertTo-XML  pour  convertir  un  ou  plusieurs  objets  en  une 
représentation  XML.  À  noter  que  ConvertTo-XML  ne  crée  pas  de  fichier,  mais  cette  action  est  de  notre 
responsabilité. 

Pour bien comprendre le fonctionnement de cette commande, prenons le petit exemple ci­après où nous avons en 
entrée  un  tableau  d’objets  personnalisé ;  ici,  des  voitures.  Ensuite,  nous  exporterons  ce  tableau  en  une 
représentation XML que nous enverrons ensuite sur disque. 

Définition du tableau d’objets : 

$voitures = @(
[PSCustomObject]@{
Marque = ’AUDI’; Modele=’A4 Avant’; Puissance = 177
},
[PSCustomObject]@{
Marque = ’BMW’; Modele=’320i’; Puissance = 200
})

Résultat avant conversion : 

PS > $voitures

Marque Modele Puissance


------ ------ ---------
AUDI A4 Avant 177
BMW 320i 200

Conversion du tableau en un flux de données texte au format XML : 

$XmlFile = $voitures | ConvertTo-Xml -as String

Résultat après conversion : 

PS > $XmlFile

<?xml version="1.0" encoding="utf-8"?>


<Objects>
<Object Type="System.Management.Automation.PSCustomObject">
<Property Name="Marque" Type="System.String">AUDI</Property>
<Property Name="Modele" Type="System.String">A4 Avant</Property>
<Property Name="Puissance" Type="System.Int32">177</Property>
</Object>
<Object Type="System.Management.Automation.PSCustomObject">
<Property Name="Marque" Type="System.String">BMW</Property>
<Property Name="Modele" Type="System.String">320i</Property>
<Property Name="Puissance" Type="System.Int32">200</Property>
</Object>
</Objects>

Envoi du résultat dans un fichier texte : 
 

PS > $XmlFile | Out-File .\voitures.xml -encoding UTF8

d. Sérialisation/désérialisation avec les commandes *­CliXML

Les  commandes  PowerShell  pour  la  manipulation  du  contenu  XML  ont  principalement  pour  vocation  le  stockage 
d’informations, et plus particulièrement le stockage d’objets. Les objets émis par PowerShell sont en réalité ceux 
du framework .NET. Ce mécanisme appelé sérialisation/désérialisation est bien connu de nos amis développeurs.  

Pour  mieux  comprendre,  prenons  un  exemple  concret.  Il  y  a  des  cas  où  nous  souhaitons  sauvegarder  dans  un 
fichier l’état d’un objet et notamment toutes ses propriétés et valeurs associées, l’objectif étant de pouvoir recréer 
fidèlement cet objet ultérieurement. C’est notamment ce qu’il se passe lorsque nous récupérons des informations 
à partir d’une machine distante via les mécanismes de communication à distance PowerShell.  

En effet, pour transiter via les protocoles HTTP/HTTPS, les données (qui sont en PowerShell toujours des objets) 
ont  besoin  d’être converties en flux texte. Nous aurons l’occasion de reparler de ces mécanismes ultérieurement 
dans cet ouvrage.  

Pour le moment, contentons­nous d’exporter les processus en cours d’exécution sur notre machine. Nous allons en 
quelque sorte prendre une photographie de l’état de notre système. Nous pourrons ainsi réimporter cet « état du 
système » par la suite et le comparer avec les processus en cours d’exécution à un autre moment de la journée. 
Cela permettrait par exemple d’identifier les processus manquants ou ceux identiques à différents instants. 

Exemple 

Sérialisation des processus en cours d’exécution. 

PS > Get-Process | Export-Clixml ./Processes.clixml

Voyons à quoi ressemble notre fichier XML, du moins les premières lignes car il est très volumineux (de l’ordre de 
plusieurs Mo) : 

PS > Get-Content ./Processes.clixml -First 15

<Objs Version="1.1.0.1"
xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Diagnostics.Process</T>
<T>System.ComponentModel.Component</T>
<T>System.MarshalByRefObject</T>
<T>System.Object</T>
</TN>
<ToString>System.Diagnostics.Process (AppleOSSMgr)</ToString>
<Props>
<I32 N="BasePriority">8</I32>
<B N="HasExited">false</B>
<Obj N="Handle" RefId="1">
<TN RefId="1">
<T>System.IntPtr</T>
...

La grammaire (le schéma) utilisée ici pour la sérialisation d’objets est propre à PowerShell. Nous pouvons nous en 
rendre  compte  grâce  à  la  balise  <Objs Version="1.1.0.1"
xmlns="http://schemas.microsoft.com/powershell/2004/04"> placée automatiquement au début 
du fichier. 

À  présent,  réimportons  la  photographie  de  l’état  des  processus  prise  précédemment  et  comparons­la  avec  les 
processus actuellement en cours d’exécution pour voir la différence. 

Exemple 

Désérialisation des processus exportés précédemment. 
PS > $Avant = Import-Clixml .\Processes.clixml

La variable  $Avant contient maintenant les processus qui s’exécutaient au moment précis où nous avons pris la 
photographie.  En  d’autres  termes,  elle  contient  le  résultat  de  la  commande  Get-Process  à  la  différence  près 
qu’un objet désérialisé perd toutes les méthodes de l’objet d’origine (mais pas les propriétés). 

Nous pouvons maintenant comparer les noms des processus (ceux qui s’exécutaient précédemment avec ceux qui 
s’exécutent en ce moment même) grâce à Compare-Object : 

PS > $Maintenant = Get-Process


PS > Compare-Object $Avant $Maintenant -Property Name

Name SideIndicator
---- -------------
chrome <=
PaintDotNet <=

Le  résultat  de  la  comparaison  effectuée  avec  Compare-Object  nous  indique  que  les  processus  chrome  et 
PaintDotNet étaient en cours d’exécution précédemment. 

9. Import/export de données au format JSON

Le  format  JSON  est  extrêmement  populaire  de  nos  jours.  C’est  le  format  le  plus  couramment  retourné  par  les 
services REST sur le Web. Il est facile de manipuler des fichiers JSON grâce au couple de commandes ConvertTo-
Json et ConvertFrom-Json. 

a. Export de données

Prenons par exemple un tableau d’objets personnalisés que nous souhaitons convertir au format JSON. Reprenons 
notre tableau de voitures, déjà utilisé précédemment avec ConvertTo-XML. 

$voitures = @(
[PSCustomObject]@{
Marque = ’AUDI’; Modele=’A4 Avant’; Puissance = 177
},
[PSCustomObject]@{
Marque = ’BMW’; Modele=’320i’; Puissance = 200
})

Résultat avant conversion : 

PS > $voitures

Marque Modele Puissance


------ ------ ---------
AUDI A4 Avant 177
BMW 320i 200
Résultat converti en JSON : 

PS > $voitures | ConvertTo-Json


[
{
"Marque": "AUDI",
"Modele": "A4 Avant",
"Puissance": 177
},
{
"Marque": "BMW",
"Modele": "320i",
"Puissance": 200
}
]

ConvertTo-Json  possède  le  paramètre  -Compress  permettant  de  retourner  une  forme  de  résultat  plus 
compacte sans saut de ligne ni indentation. 

Résultat converti en JSON compacté : 
 

PS > $voitures | ConvertTo-Json -Compress


[{"Marque":"AUDI","Modele":"A4 Avant","Puissance":177},
{"Marque":"BMW","Modele":"320i","Puissance":200}]

b. Import de données

Des  données  au  format  JSON  peuvent  être  facilement  converties  en  un  tableau  d’objets  PowerShell  grâce  à  la 
commande ConvertFrom-Json. 

Comme nous vous le disions en introduction, le format JSON est très utilisé comme format de renvoi de données 
lorsque l’on consomme des services REST sur Internet.  

Dans  l’exemple  ci­après,  nous  allons  récupérer  le  cours  du  BitCoin  (en  dollars  US)  auprès  de  la  plateforme 
d’Exchange Poloniex. 

PS > $URI = ’https://poloniex.com/public?command=returnTicker’


PS > $res = (Invoke-WebRequest -Uri $URI).content | ConvertFrom-Json
PS > $res.USDT_BTC

id : 121
last : 13447.20814455
lowestAsk : 13447.20814458
highestBid : 13447.20814455
percentChange : -0.05872196
baseVolume : 64652043.59451559
quoteVolume : 4780.90035758
isFrozen : 0
high24hr : 14449.02739320
low24hr : 12853.99999974

La  propriété  contenant  le  cours  est  visiblement  la  propriété  last.  Nous  pouvons  donc  demander  à  PowerShell 
qu’il nous retourne uniquement celle­ci. 

PS > $res.USDT_BTC.last
13447.20814455

La valeur d’un BitCoin à l’heure où nous écrivons ces lignes est donc de 13447 $. 

Ce  qui  impressionne  le  plus  ici,  ce  n’est  pas  la  valeur  du  BitCoin  (quoique...),  mais  surtout  le  fait  que 
ConvertFrom-Json  a  converti  « automagiquement »  les  données  au  format  JSON  renvoyées  par  Invoke-
WebRequest en une table de hachage qui contient un tableau de valeurs. 

10. Export de données en tant que page HTML

Si  la  création  de  pages  HTML  vous  tente  pour  présenter  quelques  rapports  stratégiques  ou  autres,  alors  la 
commandelette  ConvertTo-HTML  est  faite  pour  vous  !  En  effet,  grâce  à  celle­ci  la  génération  de  pages  Web 
devient presque un jeu d’enfant si l’on fait abstraction de la mise en forme. 

Voici les paramètres disponibles de ConvertTo-HTML : 

Paramètre  Description 

Property <Object[]>  Propriétés de l’objet passé en paramètre à écrire dans la page HTML.  

InputObject <PSObject>  Accepte un objet comme entrée. 

Body <String[]>  Spécifie le texte à inclure dans l’élément  <body>.  

Head <String[]>  Spécifie le texte à inclure dans l’élément  <head>.  

Title <String>  Spécifie le texte à inclure dans l’élément  <title>. 

Un peu à la manière de la commande Export-CSV, le nom des propriétés servira de titre pour chaque colonne du 
fichier HTML. 

Exemple 

Liste des services du système. 

PS > Get-Service | ConvertTo-HTML -Property name, displayname,


status -Title ’Services du système’ | Out-File Services.htm

Cet  exemple  nous  permet  de  créer  une  page  HTML  qui  contient  la  liste  des  services,  leurs  noms  ainsi  que  leurs 
états.  Le  paramètre  -Title  a  été  spécifié  afin  que  la  fenêtre  ait  un  titre  autre  que  celui  par  défaut.  Le  tout  est 
passé à Out-File qui créera le fichier Services.htm. 

Si  nous  ne  spécifions  pas  de  propriétés  particulières,  toutes  celles  de  l’objet  seront  écrites  ;  le  paramètre  -
Property joue donc en quelque sorte un rôle de filtre. 
D’autre  part,  à  la  différence  d’Export-CSV,  ConvertTo-HTML  a  besoin  pour  fonctionner  pleinement  qu’on  lui 
adjoigne  une  commandelette  pour  écrire  le  flux  texte  de  génération  de  la  page  dans  un  fichier.  Par  conséquent, 
n’oubliez pas de faire attention au type d’encodage du fichier résultant. 

Pour  ouvrir  ce  fichier  directement  dans  Internet  Explorer,  il  suffit  de  taper  la  commande  suivante  : 
./services.htm ou Invoke-Item ./services.htm.
Comme l’extension .htm est connue de Windows, celui­ci ouvre le fichier avec l’application qui lui est associée 
(par défaut, Internet Explorer). 

Grâce au paramètre  -Body, nous pouvons spécifier du contenu supplémentaire qui apparaîtra dans le corps de la 
page, juste avant les données de l’objet. 

Exemple 

Liste des services du système avec BODY. 

PS > Get-Service | ConvertTo-HTML -Property `


name,displayname,status -Title ’Services du système’ `
-body ’<CENTER><H2>Etat des services du système</H2></CENTER>’ |
Out-File ./Services.htm
Exemple 

Liste des services du système formaté avec CSS. 

Encore plus fort, nous allons cette fois encadrer notre tableau grâce aux feuilles de style en cascade (Cascading Style 
Sheets). Pour ce faire, nous avons créé la feuille de style suivante, que nous avons nommée Style.css : 

<style type=’text/css’>
table {
border: medium solid #000000;
border-collapse: collapse ;
}
td, th {
border: thin solid #6495ed;
}
</style>

Nous allons devoir inclure ce fichier dans l’élément HEAD de notre fichier HTML, comme ceci : 

PS > $CSS = Get-Content Style.css


PS > Get-Service | ConvertTo-HTML -Property `
name,displayname,status -Title ’Services du système’ `
-Head $CSS -Body `
’<CENTER><H2>Etat des services du système</H2></CENTER>’ |
Out-File ./Services.htm
Un dernier exemple pour terminer avec cette commande pourrait être de mettre de la couleur pour chaque ligne de 
notre table. Nous pourrions ainsi différencier les services en cours d’exécution des autres. 

Exemple 

Liste des services du système avec analyse du contenu. 

PS > Get-Service |
ConvertTo-Html -Property name,displayname,status `
-Title ’Services du système’ -Body `
’<CENTER><H2>Etat des services du système</H2></CENTER>’ |
foreach {
if($_ -match ’<td>Running</td>’)
{
$_ -replace ’<tr>’, ’<tr bgcolor=#DDDDDD>’
}
elseif($_ -match ’<td>Stopped</td>’)
{
$_ -replace ’<tr>’, ’<tr bgcolor= #6699FF>’
}
else
{
$_
}
} | Out-File ./Services.htm

Dans  cet  exemple,  lorsqu’un  service  est  en  marche,  on  remplace  la  balise  TR  (indiquant  une  ligne)  par  la  même 
balise TR avec en plus l’instruction permettant d’afficher un fond de couleur bgcolor=#codeCouleur. 
11. Export de données avec Out­GridView

Disponible uniquement sous Windows PowerShell, la commande Out-GridView permet d’afficher des données de 
façon graphique (à l’image de ce que nous venons de faire précédemment avec une page HTML, mais sans effort) et 
de manière interactive. L’interactivité de la table se trouve dans la possibilité de cliquer sur le titre des colonnes afin 
d’effectuer un tri des données par ordre alphabétique. Une autre forme d’interactivité est une fonction de recherche 
intégrée  à  la  table.  Celle­ci  est  pratique  lorsque  les  données  sont  nombreuses  et  que  l’on  en  recherche  une  en 
particulier. Sachez qu’il est possible d’utiliser  Out-GridView au milieu d’une ligne de commandes, ainsi les objets 
sélectionnés seront transmis au pipeline. 

Exemple 1 

Liste des services en cours d’exécution. 

PS > Get-Service | Out-GridView


Nous  avons  ici  cliqué  sur  la  colonne  Status  afin  de  trier  les  résultats  selon  l’état  des  services  (Running, 
Stopped, etc.). Veuillez noter qu’au­dessus des colonnes se trouve la zone de recherche dans laquelle le texte par 
défaut est Filter. 

Out-GridView peut éventuellement se substituer à un filtre Where-Object simplifié. 

Exemple 2 

Filtrage des services puis export CliXML. 

PS > Get-Service | Out-GridView -Passthru |


Export-CliXML ./Services.clixml
Utilisation de Out-GridView en mode filtre grâce au paramètre -Passthru 

Grâce au paramètre  -Passthru la sélection en mode graphique sera transmise au pipeline. Dans notre exemple, 


les objets sélectionnés seront sérialisés. 
Dates
Avec  PowerShell,  l’obtention  d’un  objet  représentant  la  date  et  l’heure  courante  se  fait  avec  la  commande  Get-
Date. Bien qu’un simple Get-Date dans la console retourne l’heure et la date actuelles, cette date peut se décliner 
en bon nombre de formats.  

Une  variable  contenant  une  date  est  de  type  DateTime.  Pour  le  vérifier  par  vous­même,  tapez  la  commande 
suivante : 

PS > (Get-Date).GetType()

IsPublic IsSerial Name BaseType


-------- -------- ---- --------
True True DateTime System.ValueType

Les  objets  de  type  DateTime  possèdent  de  nombreuses  propriétés  et  méthodes  intéressantes  comme,  entre 
autres,  la  méthode  IsDaylightSavingTime,  qui  indique  si  l’heure  actuelle  est  ajustée  pour  l’heure  d’été  ou 
l’heure d’hiver. 

Pour se rendre compte des possibilités d’actions sur les dates, le mieux est encore de faire appel à Get-Member sur 
l’objet retourné par Get-Date : 

PS > Get-Date | Get-Member

Lorsque l’on parle de date ou de temps, il est nécessaire de définir ce que l’on appelle une unité de temps. Et l’unité 
la  plus  basse  qui  soit  dans  le  système  est  appelée  un  « tick  ».  Un  tick  est  une  unité  de  mesure  du  temps.  Elle 
correspond à un battement de cœ ur  de  l’ordinateur, c’est­à­dire à une période du Timer (le Timer est le composant 
électronique qui gère le temps). Cette valeur vaut actuellement dix millionièmes de secondes. 

Pour connaître le nombre de ticks présents en une seconde, tapez la commande suivante :  $((Get-
Date).ticks) - $((Get-Date).Addseconds(-1).ticks) 

Soit à peu près 10 millions moyennant le temps de traitement de la commande. 

1. Manipulation des objets DateTime

La  commandelette  Get-Member  appliquée  à  un  objet  de  type  DateTime  retourne  une  liste  considérable  de 
méthodes et de propriétés. Le tableau suivant reprend les méthodes les plus couramment utilisées et en donne une 
brève description. 

Méthode  Description 

Add   Ajoute  ou  retranche  une  ou  plusieurs  unités  de  temps  à  l’objet 
AddDays  date.  Ajoute  si  la  valeur  passée  en  argument  est  positive, 
AddHours  retranche si la valeur passée est négative. 

AddMilliseconds 
AddMinutes 
AddMonths 
AddSeconds 
AddTicks 
AddYears 
CompareTo  Compare une date à une autre. Les valeurs retournées sont : 
-1 : si la date est antérieure à celle à laquelle on la compare. 
1 : si elle est postérieure. 
0 : si elles sont égales. 
Equals  Retourne un indicateur booléen de comparaison. 
True : si les deux dates sont identiques. 
False : dans le cas contraire. 
GetDateTimeFormats  Retourne tous les formats disponibles pour l’objet  DateTime. 

Get_Date  Les  méthodes  commençant  par  Get_*  retournent  le  paramètre 


Get_Day  de  la  date  en  question.  Exemple  :  la  méthode 
Get_DayOfWeek  Get_DayOfWeek  retourne  le  jour  de  la  semaine 
correspondant. 
Get_DayOfYear 
Get_HourGet_Millisecond 
Get_Minute 
Get_Month 
Get_Second 
Get_Ticks 
Get_TimeOfDay 
Get_Year 
IsDayLightSavingTime  Retourne  une  valeur  booléenne  qui  indique  si  l’heure  actuelle  est 
ajustée pour l’heure d’été ou l’heure d’hiver. 

Subtract  Soustrait une date de l’objet. 

ToFileTime  Retourne  la  valeur  de  l’objet  DateTime  en  cours,  en  heure  de 
fichier Windows. 

ToFileTimeUtc  Retourne  la  valeur  de  l’objet  DateTime  en  cours,  en  heure  de 
fichier Windows (Heure Universelle). 

ToLocalTime  Retourne  la  valeur  de  l’objet  DateTime  en  cours,  en  heure 
locale. 

ToLongDateString  Retourne  une  chaîne  de  caractères  contenant  la  date  au  format 
long. 

ToLongTimeString  Retourne  une  chaîne  de  caractères  contenant  l’heure  au  format 
long. 

ToOADate  Retourne  la  date  au  format  OLE  (Object  Linking  and  Embedding) 
automation  (nombre  flottant).  Le  format  OLE  automation 
correspond  au  nombre  de  jours  depuis  le  30  décembre  1899  à 
minuit. 

ToShortDateString  Retourne  une  chaîne  de  caractères  contenant  la  date  au  format 
court. 

ToShortTimeString  Retourne  une  chaîne  de  caractères  contenant  l’heure  au  format 
court. 

ToString  Retourne une chaîne de caractères contenant la date et l’heure au 
format standard. 

ToUniversalTime  Retourne la date et l’heure au format standard. 

Voici comment obtenir la liste des propriétés disponible sur un objet datetime : 

PS > Get-Date | Format-List *

DisplayHint : DateTime
DateTime : lundi 5 janvier 2015 23:07:44
Date : 05/01/2015 00:00:00
Day : 5
DayOfWeek : Monday
DayOfYear : 5
Hour : 23
Kind : Local
Millisecond : 926
Minute : 7
Month : 1
Second : 44
Ticks : 635560960649267742
TimeOfDay : 23:07:44.9267742
Year : 2015

Exemple 

Récupération des minutes dans l’heure actuelle. 

PS > (Get-Date).Minute
8

2. Formatage des dates

Dès lors que l’on parle de formats ou de formatage, il faut savoir que l’on ne va pas non plus récupérer un objet de 
type datetime, mais une chaîne (type string). En effet, un format est une représentation textuelle d’un objet. 

Le choix d’un format n’est pas forcément chose aisée, surtout quand il existe une soixantaine dits « standards ». 

Eh  oui,  il  existe  de  très  nombreuses  façons  de  représenter  une  date.  Pour  s’en  rendre  compte,  essayons  la 
commande suivante : 

PS > (Get-Date).GetDateTimeFormats() | Sort-Object -Unique

05,01,15
05.01.15 23 h 09
05.01.15 23.09
05.01.15 23:09
05.01.15 23:09:30
05.01.15 23h09
05/01/15
05/01/15 23 h 09
05/01/15 23.09
05/01/15 23:09
05/01/15 23:09:30
05/01/15 23h09
05/01/2015
05/01/2015 23 h 09
05/01/2015 23.09
05/01/2015 23:09
05/01/2015 23:09:30
05/01/2015 23h09
05-01-15
05-01-15 23 h 09
05-01-15 23.09
05-01-15 23:09
05-01-15 23:09:30
05-01-15 23h09
2015-01-05
2015-01-05 23 h 09
2015-01-05 23.09
2015-01-05 23:09
2015-01-05 23:09:30
2015-01-05 23:09:30Z
2015-01-05 23h09
2015-01-05T23:09:30
2015-01-05T23:09:30.7970279+01:00
23 h 09
23.09
23:09
23:09:30
23h09
5 janv. 15
5 janv. 15 22:09:30
5 janv. 15 23 h 09
5 janv. 15 23.09
5 janv. 15 23:09
5 janv. 15 23:09:30
5 janv. 15 23h09
5 janvier
5 janvier 2015
5 janvier 2015 22:09:30
5 janvier 2015 23 h 09
5 janvier 2015 23.09
5 janvier 2015 23:09
5 janvier 2015 23:09:30
5 janvier 2015 23h09
janvier 2015
lundi 5 janvier 2015
lundi 5 janvier 2015 22:09:30
lundi 5 janvier 2015 23 h 09
lundi 5 janvier 2015 23.09
lundi 5 janvier 2015 23:09
lundi 5 janvier 2015 23:09:30
lundi 5 janvier 2015 23h09
Mon, 05 Jan 2015 23:09:30 GMT

a. Formats standards

Pour vous aider dans le choix du format, le tableau suivant dresse la liste les formats standards applicables aux 
objets DateTime. 

Format  Description 

d  Format date courte. 
D  Format date longue. 

f  Format date longue et heure abrégée. 

F  Format date longue et heure complète. 

g  Format date courte et heure abrégée. 

G  Format date courte et heure complète. 

m,M  Format mois et jour : "dd MMMM". 

r,R  Format date et heure basé sur la spécification de la RFC 1123. 

s  Format date et heure triée. 

t  Format heure abrégée. 

T  Format heure complète. 

u  Format date et heure universelle (indicateur de temps universel : "Z"). 

U  Format date longue et heure complète avec temps universel. 

y,Y  Format année et mois. 

Voici quelques exemples d’applications des différents formats. 

Exemples 

Date au format standard tel que défini dans la RFC 1123. 

PS > Get-Date -Format r


Mon, 05 Jan 2015 23:12:00 GMT

Date au format date courte et heure complète telles que définies dans la RFC 1123. 

PS > Get-Date -Format G


05/01/2015 23:12:19

Date au format date longue et heure complète tel que défini dans la RFC 1123. 

PS > Get-Date -Format F


lundi 5 janvier 2015 23:12:40

b. Formats personnalisés

Bien  entendu  l’affichage  d’une  date  ne  se  limite  pas  aux  formats  standards.  Des  affichages  personnalisés  sont 
également possibles et ils constituent la technique la plus simple et rapide pour créer le format souhaité. 

Et pour ce faire, il faut associer le paramètre -Format aux spécificateurs de format. La différence avec les formats 
standard énoncés précédemment réside dans le fait que les formats personnalisés sont des éléments combinables 
dans une chaîne de caractères par exemple, alors que les formats standards n’ont de sens que s’ils ne sont pas 
combinés. 

Voici la liste non exhaustive des formats personnalisés : 
Format  Description 

d  Représentation du jour par un nombre compris entre : 1­31. 

dd  Représentation  du  jour  par  un  nombre  compris  entre  :  01­31.  La  différence  avec  le  format  «  d  » 
est l’insertion d’un zéro non significatif pour les nombres allant de 1 à 9. 

ddd  Représentation du jour sous la forme de son nom abrégé. Exemple : Lun., Mar., Mer., etc. 

dddd  Représentation du jour sous la forme de son nom complet. 

f  Représentation du chiffre le plus significatif de la fraction de seconde. 

ff  Représentation des deux chiffres les plus significatifs de la fraction de seconde. 

fff  Représentation des trois chiffres les plus significatifs de la fraction de seconde. 

ffff  Représentation des quatre chiffres les plus significatifs de la fraction de seconde. 

h  Représentation de l’heure par un nombre. Nombres compris entre : 1­12. 

hh  Représentation  de  l’heure  par  un  nombre  avec  insertion  d’un  zéro  non  significatif  pour  les 
nombres allant de 1 à 9. Nombres compris entre : 01­12. 

H  Représentation de l’heure par un nombre. Nombres compris entre : 0­23. 

HH  Représentation  de  l’heure  par  un  nombre  avec  insertion  d’un  zéro  non  significatif  pour  les 
nombres allant de 0 à 9. Nombres compris entre : 00­23. 

m  Représentation des minutes par un nombre. Nombres compris entre : 0­59. 

mm  Représentation  des  minutes  par  un  nombre  avec  insertion  d’un  zéro  non  significatif  pour  les 
nombres allant de 0 à 9. Nombres compris entre : 00­59. 

M  Représentation du mois par un nombre. Nombres compris entre : 1­12. 

MM  Représentation du mois par un nombre avec insertion d’un zéro non significatif pour les nombres 
allant de 1 à 9. Nombres compris entre : 01­12. 

MMM  Représentation du mois sous la forme de son nom abrégé. 

MMMM  Représentation du mois sous la forme de son nom complet. 

y  Représentation  de  l’année  sous  la  forme  d’un  nombre  à  deux  chiffres,  au  plus.  Si  l’année 
comporte  plus  de  deux  chiffres,  seuls  les  deux  chiffres  de  poids  faible  apparaissent  dans  le 
résultat et si elle en comporte moins, seuls le ou les chiffres (sans zéro significatif) apparaissent. 

yy  Idem  que  ci­dessus  à  la  différence  près  que  si  l’année  comporte  moins  de  deux  chiffres,  le 
nombre est rempli à l’aide de zéros non significatifs pour atteindre deux chiffres. 

yyy  Représentation  de  l’année  sous  la  forme  d’un  nombre  à  trois  chiffres.  Si  l’année  comporte  plus 
de  trois  chiffres,  seuls  les  trois  chiffres  de  poids  faible  apparaissent  dans  le  résultat.  Si  l’année 
comporte  moins  de  trois  chiffres,  le  nombre  est  rempli  à  l’aide  de  zéros  non  significatifs  pour 
atteindre trois chiffres. 

yyyy  Représentation de l’année sous la forme d’un nombre à quatre chiffres. Si l’année comporte plus 
de  quatre  chiffres,  seuls  les  quatre  chiffres  de  poids  faible  apparaissent  dans  le  résultat.  Si 
l’année comporte moins de quatre chiffres, le nombre est rempli à l’aide de zéros non significatifs 
pour atteindre quatre chiffres. 

Pour  obtenir  la  liste  complète  de  ces  spécificateurs  de  format,  rendez­vous  sur  le  site  MSDN  de  Microsoft  : 
http://msdn2.microsoft.com/fr­fr/library/8kb3ddd4(VS.80).aspx  

Exemple 

Dans  ce  premier  exemple,  nous  souhaitons  simplement  afficher  la  date  sous  le  format  suivant  :  <Nom du
Jour><Numero du jour> <Mois> <Année> ---- <Heure>:<Minute>:<Seconde> 

PS > Get-Date -Format ’dddd dd MMMM yyyy ---- HH:mm:ss’


lundi 05 janvier 2015 ---- 23:18:56

Exemple 

Imaginons que vous soyez amené à générer des rapports dont le nom du fichier doit correspondre à la date à laquelle il a été 
généré. 

Pour cela, rien de plus facile... 

PS > New-Item -Type file -Name `


"Rapport_$((Get-Date -Format ’dd-MM-yyyy’)).txt"

Résultat 

Mode LastWriteTime Length Name


---- ------------- ------ ---
-a--- 05/01/2015 23:19 0 Rapport_05-01-2015.txt

Il existe un dernier mode d’affichage. Ce dernier s’appelle l’affichage en mode Unix. 

Comme  vous  pouvez  l’imaginer,  ce  mode  utilise  les  spécificateurs  de  format  Unix.  Voici  l’essentiel  des 
spécificateurs : 

Format  Description 

%m  Mois de l’année (01­12). 

%d  Jour du mois (01­31). 

%y  Année, uniquement les deux derniers chiffres (00­99). 

%Y  Année sur quatre chiffres. 

%D  Affichage au format mm/dd/yy. 

%H  Heures (00­23). 

%M  Minutes (00­59). 

%S  Secondes (00­59). 

%T  Heure au format HH:MM:SS. 

%J  Jour de l’année (1­366). 

%w  Jour de la semaine (0­6) avec Samedi = 0. 

%a  Abréviation du jour (lun. , mar. , etc.). 

%h  Abréviation du mois (Fev., Juil. , etc.). 

%r  Heure au format HH:MM:SS avec HH (0­12). 

%n  Nouvelle ligne. 

%t  Tabulation. 

Exemple 

Affichage au format Unix de la date actuelle. 

 
 

PS > Get-Date -Uformat ’Nous sommes le %a %d %h %Y, et il est %T’

Nous sommes le lun. 05 janv. 2015, et il est 23:21:19

3. Manipulation des dates

a. Créer une date

Il  existe  plusieurs  manières  de  créer  une  date  en  PowerShell.  La  plus  courante  consiste  à  utiliser  la  commande 
Get-Date. Utilisée sans paramètre, cette commande retourne un objet représentant la date et l’heure courante. 
Si nous désirons créer un objet  DateTime contenant la date de notre choix, nous pouvons le spécifier grâce aux 
paramètres : -Year, -Month, -Day, -Hour, -Minute, -Second. 

Exemple 

Si nous souhaitons définir une variable qui contient la date du 1er février 2015, la commande sera la suivante :  

PS > $Date = Get-Date -Year 2015 -Month 2 -Day 1

Notez que tout paramètre qui n’est pas précisé prend la valeur correspondante de la date actuelle. 

b. Modifier une date

Lors  de  l’exécution  d’un  script  ou  pour  une  application  tierce  nous  pouvons  être  amenés à  modifier  une  date 
donnée. Pour répondre à cela, il faut utiliser la famille des méthodes Add*. 

Les méthodes  Add  permettent  d’ajouter un entier relatif de jours avec  AddDays, d’heures  avec  AddHours, de 


millisecondes  avec  AddMilliseconds,  de  mois  avec  AddMonth,  de  secondes  avec  AddSeconds,  d’années 
avec AddYears et de ticks avec AddTicks. 

Les entiers relatifs sont l’ensemble des entiers (0,1,2,3...) positifs et négatifs (0,­1,­2,­3...). 

Par  exemple,  pour  savoir  quel  jour  de  la  semaine  sera  le  même  jour  qu’aujourd’hui  mais  dans  un  an,  il  suffit 
d’ajouter un an à la date du moment et de récupérer le jour de la semaine correspondant. 

PS > $date = Get-Date


PS > $date.AddYears(1).DayOfWeek

Monday

De la même façon, il est facile de retrouver le jour de sa naissance. 

Exemple 

PS > $date = [DateTime]’10/03/1974’


PS > $date.DayOfWeek
Thursday

Lorsque  l’on  spécifie  une  date  comme  dans  l’exemple  ci­dessus,  le  format  attendu  est  le  format  anglo­saxon,  à 
savoir : mois/jour/année. 

c. Comparer des dates

Il  existe  plusieurs  types  de  comparaison  de  dates,  la  comparaison  la  plus  simple  s’effectue avec  la  méthode 
CompareTo.  Appliquée  à  la  variable  de  type  DateTime,  cette  méthode  permet  une  comparaison  rapide  et 
renvoie les valeurs suivantes : 

Valeur de retour  Description 

-1  Si la date est antérieure à celle à laquelle on la compare. 

1  Si elle est postérieure. 

0  Si elles sont égales. 

Exemple 

Comparaison de la date de deux fichiers. 

Pour cela, il suffit de récupérer une à une les dates de création et de les comparer avec la méthode CompareTo. 

PS > $Date_fichier_1 = (Get-item Fichier_1.txt).Get_CreationTime()


PS > $Date_fichier_2 = (Get-item Fichier_2.txt).Get_CreationTime()
PS > $Date_fichier_1.CompareTo($date_fichier_2)
-1

d. Calculer un intervalle entre deux dates

Il  est  très  facile  de  calculer  le  temps  écoulé  entre  deux  dates.  Cette  opération  est  rendue  possible  grâce  à  la 
commandelette New-TimeSpan. Le résultat de cette commande émet non pas un objet DateTime mais un objet 
TimeSpan. 

Exemple 

Calcul du temps écoulé depuis votre naissance. 

Pour  déterminer  le  nombre  de  secondes  qui  se  sont  écoulées  depuis  votre  naissance,  il  faut,  dans  un  premier 
temps, calculer le temps écoulé grâce à la commande  New-TimeSpan. Puis dans un second temps, récupérer la 
propriété TotalSeconds, comme ci­dessous. 

Construisons d’abord la variable $DateNaiss qui recevra notre date de naissance : 

PS > $DateNaiss = Get-Date -Year 1985 -Month 10 -Day 6 -Hour 8


-Minute 30

Nous pouvons également la construire ainsi, c’est au choix : 
PS > $DateNaiss = [datetime]’1985/10/06 08:30’

Puis nous faisons appel à  New-TimeSpan et lui passons la variable contenant la date de naissance ainsi que la 
date et heure courante : 

PS > New-TimeSpan -Start $DateNaiss -End (Get-Date)

Days : 10683
Hours : 14
Minutes : 54
Seconds : 10
Milliseconds : 333
Ticks : 9230648503339945
TotalDays : 10683,6209529397
TotalHours : 256406,902870554
TotalMinutes : 15384414,1722332
TotalSeconds : 923064850,333994
TotalMilliseconds : 923064850333,994

À présent, il n’y a plus qu’à sélectionner la propriété TotalSeconds ainsi : 

PS > (New-TimeSpan -Start $DateNaiss -End (Get-Date)).TotalSeconds

923064911,014729

La  commande  New-TimeSpan  retourne  un  objet  de  type  TimeSpan.  Pour  observer  toutes  les  méthodes 
applicables au type TimeSpan, tapez la commande suivante : New-Timespan | Get-Member. 

e. Conversion d’une date exprimée en ticks

Il  arrive  relativement  fréquemment  que  nous  recevions  des  valeurs  entières  longues  pour  exprimer  des  dates 
comme  par  exemple  une  valeur  du  genre  « 130088918630153620 ». Une  telle  valeur  correspond  au  nombre  de 
ticks écoulés depuis le 1e r janvier de l’an 1601 à 0h00.  

C’est  le  cas  par  exemple  des  dates  retournées  par  l’API  ADSI  lorsque  l’on  manipule  Active Directory  Domain 
Services mais c’est aussi le cas de certaines classes .NET. 

Dans un cas de figure de cette espèce, pas de panique ! Bien que PowerShell ne dispose pas de commandes pour 
la  conversion  d’une  telle  date,  nous  allons  quand  même  pouvoir  nous  en  sortir  en  attaquant  directement  le 
framework .NET. 

En effet, la classe  DateTime permet nativement de prendre en charge un tel format, ainsi nous pouvons écrire 
ceci : 

PS > [DateTime]130088918630153620

mercredi 27 mars 0413 21:35:00


Bien  que  le  résultat  semble  correct,  il  y  a  cependant  un  souci.  Le  problème,  c’est  que  la  date  retournée  est  au 
format UTC (Coordinated Universal Time). C’est­à­dire que primo elle commence à l’an 1, et secundo elle ne tient pas 
compte du fuseau horaire sur lequel nous sommes. Ainsi, nous nous retrouverons avec une heure de différence si 
l’on ne prend pas en compte ce détail. 

Afin  « d’augmenter » une  date,  il  suffit  de  lui  ajouter  des  années  grâce  à  la  méthode  AddYears().  Ainsi,  pour 
ajuster le résultat nous devons lui ajouter 1600 années : 

PS > ([DateTime]130088918630153620).AddYears(1600)

mercredi 27 mars 2013 21:04:23

À présent, il nous faut ajuster la date UTC afin de la convertir en date locale, c’est­à­dire dans un format tenant 
compte du fuseau horaire sur lequel nous sommes.  

Pour  récupérer  le  fuseau  horaire,  nous  allons  utiliser  la  classe  TimeZoneInfo  et  en  particulier  sa  propriété 
statique Local, tel qu’indiqué ci­dessous : 

PS > [TimeZoneInfo]::Local

Id : Romance Standard Time


DisplayName : (UTC+01:00) Bruxelles, Copenhague, Madrid, Paris
StandardName : Paris, Madrid
DaylightName : Paris, Madrid (heure d’été)
BaseUtcOffset : 01:00:00
SupportsDaylightSavingTime : True

La dernière étape consiste à modifier notre date en lui appliquant le fuseau horaire. Pour ce faire, nous utiliserons 
la méthode statique ConvertTimeFromUtc(), toujours de la classe TimeZoneInfo : 

PS > $myUTCTime = ([DateTime]130088918630153620).AddYears(1600)


PS > [TimeZoneInfo]::ConvertTimeFromUtc($myUTCTime, [TimeZoneInfo]::Local)

mercredi 27 mars 2013 22:04:23

Pour clôturer cette partie, nous allons transformer ce petit bout de script bien utile en une fonction car nous nous 
en resservirons plus loin dans cet ouvrage. 

C’est ainsi que nous pouvons écrire la fonction suivante : 

function ConvertTo-LocalTime
{
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[Int64]$LongDate
)
$myUTCTime = ([DateTime]$LongDate).AddYears(1600)
[TimeZoneInfo]::ConvertTimeFromUtc($myUTCTime, [TimeZoneInfo]::Local)
}

À présent, testons notre fonction : 

PS > ConvertTo-LocalTime -LongDate 130088918630153620

mercredi 27 mars 2013 22:04:23

Vous aimerez peut-être aussi