Vous êtes sur la page 1sur 38

La gestion des erreurs sous PowerShell.

Par Laurent Dardenne, le 03/09/2013.

Niveau

A Julien D. pour sa patience.


Conu avec Powershell v2 sous Windows Seven.
Je tiens remercier Matthew B. et Laurent C. pour leurs relectures et remarques.

Site de lauteur : http://laurent-dardenne.developpez.com/


Les fichiers sources :
http://ottomatt.pagesperso-orange.fr/Data/Tutoriaux/Powershell/La-gestion-des-erreurs-sousPowerShell/Sources.zip

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 1 / 38

Chapitres
1

LERREUR EST HUMAINE............................................................................................................................ 4

LES FLUX A DISPOSITION DANS POWERSHELL ..................................................................................5


2.1 ERREUR SIMPLE ET ERREUR BLOQUANTE .........................................................................................................5
2.1.1
Comportement dune erreur ..................................................................................................................5
2.1.2
Comportement dune erreur bloquante..................................................................................................6
2.2 FLUX DERREUR ...............................................................................................................................................7

PRINCIPE DES EXCEPTIONS ....................................................................................................................... 7


3.1 CONCEPT DEXCEPTION ....................................................................................................................................9
3.1.1
Usage .....................................................................................................................................................9
3.2 DECLENCHER UNE ERREUR ............................................................................................................................ 10
3.3 DECLENCHER UNE ERREUR BLOQUANTE ........................................................................................................ 10
3.3.1
Propager la cause relle dune erreur ................................................................................................. 11

MODIFIER LE COMPORTEMENT DE LA GESTION DERREUR ...................................................... 13


4.1
4.2
4.3
4.4

LA STRUCTURE ERRORRECORD ..................................................................................................................... 14


MODIFIER LE COMPORTEMENT DE WRITE-ERROR .......................................................................................... 15
MODIFIER LAFFICHAGE DES MESSAGES DERREUR........................................................................................ 17
MODIFIER DAUTRES COMPORTEMENTS ......................................................................................................... 19

LA CONSTRUCTION DUN GESTIONNAIRE DEXCEPTION ............................................................. 19


5.1 TRY ................................................................................................................................................................ 19
5.2 CATCH ........................................................................................................................................................... 20
5.2.1
Accs lobjet Exception ..................................................................................................................... 20
5.2.2
Comportement avec une erreur simple ................................................................................................ 20
5.2.3
Une construction viter ..................................................................................................................... 21
5.2.4
Capture par type dexception............................................................................................................... 22
5.2.1
Redclenchement dexception .............................................................................................................. 24
5.2.2
Gestion dexception dans le pipeline ................................................................................................... 24
5.2.3
Comment dterminer les exceptions capturer ................................................................................... 25
5.3 FINALLY ......................................................................................................................................................... 26
5.4 PROPAGATION DES EXCEPTIONS IMPREVUES .................................................................................................. 28
5.5 LINSTRUCTION TRAP .................................................................................................................................... 29

PARAMETRES COMMUNS DE CMDLET OU DE FONCTION LIES AUX ERREURS ..................... 29


6.1
6.2
6.3
6.4

ERRORACTION ............................................................................................................................................... 29
ERRORVARIABLE ........................................................................................................................................... 29
WARNINGVARIABLE ...................................................................................................................................... 30
COMMENT IMPLEMENTER CE TYPE DE VARIABLE ? ........................................................................................ 30

GESTIONNAIRE DEXCEPTION GLOBALE ........................................................................................... 31

GENERER DES CLASSES DEXCEPTION ................................................................................................ 32


8.1
8.2

TYPE DEXCEPTION UTILISABLE ..................................................................................................................... 32


CREER SES PROPRES EXCEPTIONS ................................................................................................................... 32

QUELQUES OPERATIONS RECURRENTES ........................................................................................... 34


9.1
9.2
9.3
9.4

TESTER SI UNE ERREUR A EU LIEU .................................................................................................................. 34


DETERMINER LE RETOUR DEXECUTION DUNE COMMANDE .......................................................................... 34
REDIRECTION DERREUR ................................................................................................................................ 35
FLUX STANDARD ............................................................................................................................................ 37

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 2 / 38

9.4.1
Les nouveaux flux sous Powershell version 3 ...................................................................................... 37
9.5 PROPRIETE DE FORMATAGE ............................................................................................................................ 38
10

CONCLUSION................................................................................................................................................. 38

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 3 / 38

1 Lerreur est humaine


La programmation tant un exercice difficile et sans remde miracle, en cas
derreur il savre judicieux de dterminer ce qui ne fonctionne pas, o et
pourquoi. Nous devons donc considrer une erreur comme une information
importante.
On oublie le plus souvent que lon code, pour se faciliter le travail, dans un
environnement contrl (tous les droits, toutes les ressources disponibles).
Linstallation dun script dans lenvironnement de production peut rvler des
erreurs imprvues, voir quelques fois insouponnes. Les tests tant l pour valider
le respect des spcifications et les scnarios derreur les plus pertinents. Les autres
erreurs, le plus souvent par manque de temps, ne sont pas tests et seront
remontes par le mcanisme de gestion derreur global et corriges au cas par cas.
Dans une gestion derreur on doit se proccuper de ses propres cas derreurs, mais
aussi de ceux des autres. Pour ces derniers, il sagit dinformations destines aux
dveloppeurs utilisant :
des programmes, des cmdlets ou des scripts tiers,
des ressources du systme (plus de mmoire, plus despace disque,).
Coder cest une aventure, vous dviter les chausse-trapes !

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 4 / 38

2 Les flux disposition dans Powershell


On peut utiliser un mcanisme de traces pour retrouver le contexte ou les traitements prcdant
lerreur. Dans ce cas on utilisera soit le flux Debug utilis lors de la phase de mise au point, soit
le flux Verbose qui lui permettra dafficher des informations supplmentaires juges optionnelles
lors de lexcution en production. Ces flux pourront tre activs ou dsactivs laide dune
variable de prfrence, cf. About_Preference_Variable.txt.
Je vous recommande toutefois dutiliser un systme de log plus labor, tel que Log4NET qui
permet dadresser plusieurs dispositifs.
Powershell propose galement un flux spcifique ddi aux erreurs.
2.1

Erreur simple et erreur bloquante

Powershell utilisant le pipeline pour manipuler des collections dobjets, ses concepteurs ont
dcids de scinder le comportement des erreurs. Sous Powershell une erreur est bloquante ou
pas.
Les termes anglais tant respectivement Terminating Errors et Non-Terminating Errors qui
peuvent se traduire par mettre fin, ou pas, quelque chose.
Vos traitements dtermineront si vous avez besoin de traiter leurs erreurs en tant querreur
simple ou en tant querreur bloquante. Lusage en anglais du non- rend confus la
comprhension de cette distinction, puisque smantiquement une erreur est une erreur, je
parlerais donc derreur et derreur bloquante.
2.1.1 Comportement dune erreur
Elle narrte pas le traitement lors de son dclenchement, mais reste une information importante
mmoriser, elle nest pas li une exception, mais plutt une trace derreur temporaire. La
situation la dclenchant nest pas considre comme bloquante. Ceci dit par dfaut on avertit tout
de mme lutilisateur :
$DebugPreference=Continue
Function Test-TypeErreur{
Write-Debug "Debut"
$process = Get-WmiObject Win32_Process -computername "offline"
Write-Debug "Suite"
1..3|
Where-Object

{($_

% 2) -ne 0}|

Foreach-Object {Write-Error "Nombre impaire interdit."}


Write-Debug "Fin"
}
Test-TypeErreur

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 5 / 38

DBOGUER : Debut
Get-WmiObject : Le serveur RPC n'est pas disponible. (Exception de HRESULT : 0x800706BA)
Au niveau de ligne : 3 Caractre : 28
DBOGUER : Suite
Test-TypeErreur : Nombre impaire interdit.
Au niveau de ligne : 10 Caractre : 16
Test-TypeErreur : Nombre impaire interdit.
Au niveau de ligne : 10 Caractre : 16
DBOGUER : Fin

Dans cet exemple, trois erreurs sont dclenches,

une lors de lexcution du traitement du cmdlet Get-WmiObject,

les deux autres par la boucle Foreach-Object.

Mais aucune narrte le droulement du code de la fonction. Notez que

le rsultat de laffichage a t tronqu afin de faciliter la lecture,

les traces de debug sont actives.

2.1.2 Comportement dune erreur bloquante


Dans un premier temps, elle arrte le traitement lors de son dclenchement, car elle est lie au
mcanisme dexception que nous verrons par la suite.
Dans un second temps, la situation la dclenchant est suffisamment importante pour informer le
code appelant ou lutilisateur. Ce peut tre par exemple une condition interne empchant la
poursuite du traitement (une division par zro) ou vous ne voulez pas que votre traitement se
poursuive suite une condition particulire, droits insuffisants, invalidation dune rgle de
gestion, etc.
$DebugPreference=Continue
Function Test-TypeErreur{
Write-Debug Debut
$process = Get-WmiObject Win32_Process -computername "offline"
Write-Debug Suite
1..3|
Where-Object

{($_

% 2) -ne 0}|

Foreach-Object {Throw "Nombre impaire interdit."}


Write-Debug fin
}
Test-TypeErreur

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 6 / 38

DBOGUER : Debut
Get-WmiObject : Le serveur RPC n'est pas disponible. (Exception de HRESULT : 0x800706BA)
Au niveau de ligne : 3 Caractre : 28
DBOGUER : Suite
Test-TypeErreur : Nombre impaire interdit.
Au niveau de ligne : 10 Caractre : 16

Dans cet exemple modifi, une erreur est dclenche et une erreur bloquante arrte le
droulement du code la fonction, laffichage de la trace de debug Suite ne se fait donc pas.
On constate entre les deux types derreur, que pour une itration dans le pipeline le
dclenchement dune erreur est un moyen simple dinformer lutilisateur dune erreur sur un ou
des objets de la collection, tout en continuant traiter le reste de la collection.
Par exemple litration sur une collection de nom de serveur afin de collecter des informations,
est un parfait exemple dutilisation derreur. On souhaite continuer le traitement sur le reste de la
collection.
En revanche la distribution de ressources vers des serveurs dune ferme, peux nous inciter
arrter le traitement ds la premire erreur rencontre (limplmentation dun mcanisme de rollback ne
sera pas traite dans ce tutoriel).
Cest donc vous de dterminer quand utiliser lun ou lautre type derreur.
Pour les objets dotnet, qui ne sont pas des cmdlets, leur code dclenchera toujours des
erreurs bloquantes.
Pour les cmdlets ce sera soit lun soit lautre selon le choix de son concepteur.
2.2

Flux derreur

Chaque erreur est insre dans la collection derreur accessible via la variable automatique
nomme $Error qui est cre lors du dmarrage dune session ou dun job.
Laffichage de cette collection renverra toutes les erreurs dclenches depuis le dmarrage de
votre session Powershell. Linstruction $Error[0] renverra la dernire erreur ayant eu lieu.
Lapproche utilise dans le code suivant :
If ($Error.count eq 0) {Write-Host Russite.}

ne doit pas tre utilise. Suite des bugs dans le parseur de Powershell, la collection $Error
peut contenir de fausses erreurs. La version 3 de Powershell reste concerne par ces bugs.
Consulter le site MsConnect pour plus de dtails.
Lusage du paramtre ErrorVariable prsent plus avant nest pas concern par cette restriction.

3 Principe des exceptions


Les API de Windows ont t cres laide du langage C, une poque o la gestion des erreurs
se faisait par un code retour indiquant la nature de lerreur tout en lassociant un message
derreur localisable.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 7 / 38

Association que lon peut retrouver avec la commande suivante :


net helpmsg 2182
Le service demand a dj t dmarr.

Et pour ceux de Winrm avec :


winrm helpmsg 0x5
Accs refus.

Avec cette approche, chaque appel de mthode renvoyant un code retour doit tre suivi dun test
de russite. Cette gestion est sous la responsabilit du dveloppeur appelant ces fonctions, mais
aucun mcanisme ne garantit que lappelant prenne bien en charge le code retour.
Cette gestion derreur ressemble au schma suivant, le code regroupe les traitements fonctionnels
et le traitement des erreurs :
Code

Code fonctionnel
+
gestion derreurs

Pour faciliter limplmentation dune gestion derreur, un mcanisme dexception a t mis en


uvre dans les langages de programmation plus rcents. Les exceptions sous Powershell sont
considres comme des erreurs bloquantes et pourront tre interceptes.
Dans le schma suivant, le code de la gestion des erreurs est ici spar du code fonctionnel :
Code

Code fonctionnel

Gestion derreurs

Chaque bloc est ddi. De plus, la gestion derreur peut tre dclare dans le bloc de code
appelant.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 8 / 38

Voici le code du principe dune gestion dexception :


Try
{ Code Fonctionnel }
Catch
{ Gestion derreurs }

3.1

Concept dexception

Comme indiqu sur le site MSDN (http://msdn.microsoft.com/fr-fr/library/bb727317.aspx) :


Une des raisons pour lesquelles les exceptions ne sont pas appeles des erreurs est que le
terme erreur laisse entendre en gnral une faute de programmation. Une exception est une
violation des hypothses implicites d'une routine.
Par exemple, lors dune copie, on suppose la cible existante ainsi que les droits ncessaires
positionns. Une exception est donc une condition derreur stoppant lexcution du code en cours
et gnrant une rupture de squence :
Code

Dclenchement
dune exception

Code fonctionnel

Gestion derreurs

Avantages, par rapport aux codes retour : on peut la traiter dans un bloc de code diffrent de
celui la dclenchant et surtout, par dfaut elle ne peut pas tre ignore.
Cette exception, cre par le framework dotNet, prend la forme dun objet portant des
informations sur la condition derreur, l o un code retour ne peut pas porter plus dinformation
quun entier, moins de renvoyer une structure de donnes.
Une exception peut provenir du matriel (processeur, carte rseau), du noyau de lOS ou le plus
souvent dune mthode objet ou dune API.
Note : Pour les schmas, jai repris la prsentation de louvrage "Oracle PL/SQL Programming"
de Steven Feuerstein.
3.1.1 Usage
La mcanique dexception permet dcrire du code sans se soucier des erreurs pouvant survenir
(un fichier inexistant, pas de droits sur la ressource cible, plus de mmoire). On code les
traitements sans vrifier si chaque instruction, pouvant dclencher une exception, russie. Ce

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 9 / 38

type dcriture facilite la relecture du code, car il spare le code fonctionnel du code de gestion
des erreurs.
A la diffrence des API win32, le framework dotnet, et donc Powershell, utilise un mcanisme
dexception. Le framework permet de dclencher des exceptions personnalises laide dune
classe Exception, et de ses descendants, mais aussi dintervenir si besoin sur lexcution du
mcanisme dexception laide de mots-cl du langage.
A laide de ceux-ci on peut par exemple capturer lexception afin de corriger la condition
derreur ou sauvegarder les donnes avant larrt inopin du programme. Une fois ceci fait on
peut redclencher lexception pour terminer le programme.
Qui dit gestion dexception dit gestionnaire dexception. Son rle est dintercepter une, plusieurs
ou toutes les exceptions dclenches dans un script, une fonction ou un bloc de code.
3.2

Dclencher une erreur

Pour gnrer une erreur, on utilisera le cmdlet Write-Error. Celui-ci attend, dans sa forme la plus
simple, une chane de caractres :
Exemple :
$Tableau=@(Un,Deux)
$Name=Trois
if ($Tableau notContains $Name)
{ Write-Error "Llment $Name nexiste pas."}
if ($Tableau -notContains $Name)
{ Write-Error "L'lment '$Name' n'existe pas."} : L'lment 'Trois' n'existe pas.

Dans une console, le rsultat dun appel Write-Error saffiche par dfaut lcran.
3.3

Dclencher une erreur bloquante

Pour gnrer une erreur bloquante, on dclenchera une exception laide de linstruction Throw.
Celle-ci attend dans sa forme le plus simple une chane de caractres :
$Name=
if ($Name -eq [string]::Empty)
{ Throw "Le paramtre Name doit tre renseign."}
throw : Le paramtre 'Name' doit tre renseign.

Ici la classe de lexception dclenche sera System.Management.Automation.RuntimeException.


On peut galement lui passer en paramtre une instance dobjet de la classe Exception ou drive
de cette classe :
if (-not (Test-Path Function:\TestInconnue))
{
$ObjetException=New-Object System.NotImplementedException(
"La fonction TestInconnue n'existe pas.")
Throw $ObjetException
}

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 10 / 38

throw : La fonction TestInconnue n'existe pas.

Ici la classe de lexception dclenche sera System.NotImplementedException.


Note : La variable automatique $MaximumErrorCount permet de modifier la taille maximum de
la collection $Error. Une fois la taille maximum atteinte, Powershell supprimera lerreur la plus
ancienne afin dinsrer la plus rcente en dbut de collection.
3.3.1 Propager la cause relle dune erreur
Le plus souvent le message associ une erreur est une explication de lerreur :
Try {
$msg="Largument nest pas renseign."
$Exception=New-Object System.ArgumentException($Msg,Name)
throw $Exception
}
Catch {
throw Traitement en erreur : $($_.Exception.Message) "
}
throw : Traitement en erreur : L'argument n'est pas renseign.
Nom du paramtre : Name

Cette approche ne permet pas de retrouver le contexte de lerreur, cest--dire la cause de son
dclenchement port par la premire exception :
$Error[0].Exception.Innerexception -eq $null
True

En revanche celle-ci le permet :


Try {
$msg="Largument nest pas renseign."
$Exception=New-Object System.ArgumentException($Msg,Name)
throw $Exception
}
Catch [System.ArgumentException] {
$Msg="Traitement en erreur :"+ $_.Exception.Message
$Exception=New-Object System.ApplicationException($Msg,$_.Exception)
throw $Exception
}

Ainsi lexception dorigine est propage, ce qui vite de parcourir la collection $Error afin de
reconstruire lenchanement des erreurs. A la diffrence de la construction prcdente, ici la
proprit InnerException est renseigne :
$Error[0].Exception.Innerexception -eq $null
False
$Error[0].Exception.Innerexception
L'argument n'est pas renseign.
Nom du paramtre : Name

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 11 / 38

La fonction Resolve-Error, disponible dans les sources, vous permettra dafficher plus
facilement le contexte et les niveaux dimbrication :
Resolve-Error
PSMessageDetails
:
Exception
: System.ApplicationException: Traitement en erreur :L'argument n'est pas renseign.
Nom du paramtre : Name ---> System.ArgumentException: L'argument n'est pas renseign.
Nom du paramtre : Name
--- Fin de la trace de la pile d'exception interne --TargetObject
:
CategoryInfo
: OperationStopped: (:) [], ApplicationException
FullyQualifiedErrorId : Traitement en erreur :L'argument n'est pas renseign.
Nom du paramtre : Name
ErrorDetails
:
InvocationInfo
: System.Management.Automation.InvocationInfo
PipelineIterationInfo : {}
MyCommand
:
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 9
OffsetInLine : 7
HistoryId
: 22
ScriptName
:
Line
: throw $Exception
PositionMessage :
Au niveau de ligne : 9 Caractre : 7
+ throw <<<< $Exception
InvocationName : throw
PipelineLength : 0
PipelinePosition : 0
ExpectingInput : False
CommandOrigin : Internal
00000000000000000000000000000000000000000000000000000000000000000000000000000000
Message

: Traitement en erreur :L'argument n'est pas renseign.


Nom du paramtre : Name
Data
: {}
InnerException : System.ArgumentException: L'argument n'est pas renseign.
Nom du paramtre : Name
TargetSite :
StackTrace :
HelpLink
:
Source
:
11111111111111111111111111111111111111111111111111111111111111111111111111111111
Message
: L'argument n'est pas renseign.
Nom du paramtre : Name
ParamName
: Name
Data
: {}
InnerException :
TargetSite :
StackTrace :
HelpLink
:
Source
:

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 12 / 38

4 Modifier le comportement de la gestion derreur


La variable de prfrence $ErrorActionPreference paramtre le comportement de la gestion
des erreurs. Ses valeurs valides sont :
Stop (Arrter)

Affiche le message d'erreur et arrte l'excution.

Inquire (Demander)

Affiche le message d'erreur et vous demande si vous


souhaitez continuer.
Attention ce paramtrage ne pourra tre utilis lors de
lexcution dun script dans un Job ou dans une console
Orchestrator.

Continue (Continuer)

Affiche le message d'erreur et continue l'excution lors


dun appel Write-Error ou stop lexcution lors dun
appel Throw.

Valeur par dfaut


SilentlyContinue

Aucune erreur narrte l'excution.

(Continuer en mode silencieux)

Le message nest pas affich sur la console, l'excution


continue sans interruption.
La variable $Error est renseigne.

La porte de cette variable automatique est locale.


Reprenons lexemple dclenchant des erreurs et modifions le comportement :
$ErrorActionPreference=Stop
Function Test-TypeErreur{
#Pour le test, dcommentez la igne suivante
#$ErrorActionPreference="SilentlyContinue" # porte LOCALE
Write-Host "Debut"
$process = Get-WmiObject Win32_Process -computername "offline"
Write-Host "Suite"
1..3|
Where-Object

{($_

% 2) -ne 0}|

Foreach-Object {Write-Error "Nombre impaire interdit."}


Write-Host "Fin"
}
Test-TypeErreur
Debut
Get-WmiObject : Le serveur RPC n'est pas disponible. (Exception de HRESULT : 0x800706BA)
Au niveau de ligne : 3 Caractre : 28

Avec ce paramtrage, le code de la fonction est stopp ds la cration dune erreur sans
distinction de catgorie.
Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 13 / 38

On peut aussi ne pas tenir compte des erreurs bloquantes (des exceptions), en utilisant la valeur
SilentlyContinue :
$Error.Clear()
$ErrorActionPreference="SilentlyContinue"
Function Test-TypeErreur{
Write-Host "Debut"
$process = Get-WmiObject Win32_Process -computername "offline"
Write-Host "Suite"
1..3|
Where-Object

{($_

% 2) -ne 0}|

Foreach-Object {Throw "Nombre impaire interdit."}


Write-Host "Fin"
}
Test-TypeErreur

Lexcution de cette fonction affichera :


Debut
Suite
Fin

Je trouve cet usage plutot inhabituel, notez que la collection derreurs contient bien toutes les
erreurs cres, bien que celles-ci ne soient pas affiches :
$Error
throw : Nombre impaire interdit.
Au niveau de ligne : 7 Caractre : 26
+ Foreach-Object {Throw <<<< "Nombre impaire interdit."}
throw : Nombre impaire interdit.
Au niveau de ligne : 7 Caractre : 26
+ Foreach-Object {Throw <<<< "Nombre impaire interdit."}
Get-WmiObject : Le serveur RPC n'est pas disponible. (Exception de HRESULT : 0x800706BA)
Au niveau de ligne : 3 Caractre : 28
+ $process = Get-WmiObject <<<< Win32_Process -computername "offline"

Voir aussi les exemples de laide en ligne :


Get-Help Preference_Variable

4.1

La structure ErrorRecord

Lanalyse dune erreur ncessite de connaitre la classe ErrorRecord, vous retrouverez le dtail de
ses membres sur le lien suivant :
http://msdn.microsoft.com/fr-FR/library/system.management.automation.errorrecord_members.aspx

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 14 / 38

4.2

Modifier le comportement de Write-Error

Si la variable $ErrorActionPreference est assigne Stop, un appel Write-Error dclenchera


une exception du type System.Management.Automation.ActionPreferenceStopException :
$Error.Clear()
$ErrorActionPreference="Stop"
Function Test-Error {Write-Error "Test"}
Test-Error
Test-Error : Test

Laffichage de la dernire erreur renvoie le texte du message derreur :


$Error[0]
L'excution de la commande s'est arrte, car la variable de prfrence ErrorActionPreference ou le
paramtre courant a la valeur Stop : Test

Affichons le type de lerreur :


$Error[0].GetType().FullName
System.Management.Automation.ActionPreferenceStopException

Laffichage des proprits de la dernire erreur renvoie les dtails suivants :


$Error[0]|select *
ErrorRecord
: Test
WasThrownFromThrowStatement : False
Message
: L'excution de la commande s'est arrte, car la variable de prfrence
ErrorActionPreference ou le paramtre courant a la valeur Stop : Test
Data
: {}
InnerException
:
TargetSite
: System.Collections.ObjectModel.Collection`1[System.Management.Automation.
PSObject] Invoke(System.Collections.IEnumerable)
HelpLink
:
Source
: System.Management.Automation

On constate que lerreur contient un champ ErrorRecord dtaillant lerreur gnre par lappel
Write-Error. Son affichage renverra :
$Error[0].ErrorRecord|select *
PSMessageDetails
:
Exception
: Microsoft.PowerShell.Commands.WriteErrorException: Test
TargetObject
:
CategoryInfo
: NotSpecified: (:) [Write-Error], WriteErrorException
FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-Error
ErrorDetails
:
InvocationInfo
: System.Management.Automation.InvocationInfo
PipelineIterationInfo : {0, 0}

A son tour, laffichage de la proprit imbrique Exception renvoie les dtails suivants :
$Error[0].ErrorRecord.Exception|select *
Message
: Test
Data
: {}
InnerException :
TargetSite :
StackTrace :
HelpLink
:
Source
:

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 15 / 38

Pour cet exemple, le dtail porte peu dinformations.


Pour obtenir des informations sur le contexte de l'erreur, on affiche le contenu de la proprit
InvocationInfo :
$Error[0].ErrorRecord.InvocationInfo |Select *
MyCommand
: Test-Error
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 1
OffsetInLine
: 11
HistoryId
: 17
ScriptName
:
Line
: Test-Error
PositionMessage :
Au niveau de ligne : 1 Caractre : 11
+ Test-Error <<<<
InvocationName : Test-Error
PipelineLength
:1
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Runspace

Selon le contexte dexcution, on peut donc connaitre le nom du script, le nom de la fonction et
le numro de la ligne provoquant lerreur.
Sous Powershell version 3, la classe ErrorRecord propose un nouveau membre :
$Error[0].StackTrace

En revanche si on modifie la variable $ErrorActionPreference afin dintercepter lexception


dans un bloc catch, le contenu diffre :
$Error.Clear()
$ErrorActionPreference="Stop"
Function Test-Error {
Try {
Write-Error "Test"
} catch [System.Management.Automation.ActionPreferenceStopException]{
Write-Warning "Erreur gre"
Write-Host "`r`n------- Dtail exception courante`r`n"
$_
$_.GetType().FullName
$_.ErrorRecord|select * #Aucun affichage
$_|select * #Aucun affichage
}
}
Test-Error

Dans ce cas, la variable $_ est toujours une instance de la classe ErrorRecord hbergeant une
instance d'exception.
Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 16 / 38

Affichons le type de lerreur :


$Error[0].GetType().FullName
System.Management.Automation.ErrorRecord

Lerreur contenue dans $Error[0] est bien lerreur gnre par lappel Write-Error, mais elle
ne contient plus ici les informations de lexception ActionPreferenceStopException :
$Error[0].ErrorRecord -eq $null
True

Ce comportement est identique pour toutes les erreurs simples stoppes. Selon le cas on accdera
aux informations de lerreur soit par :
$Error[0].ErrorRecord.Exception

Exemple :
$Error.Clear()
$ErrorActionPreference="Stop"
Dir x:\

#Suppose le lecteur X inexistant

$Error[0]
$Error[0].ErrorRecord|select *
$Error[0].ErrorRecord.Exception|select *

Soit par :
$Error[0].Exception

Exemple :
$Error.Clear()
$ErrorActionPreference="Continue"
Dir x:\
$Error[0]
$Error[0]|select *
$Error[0].Exception|select *

4.3

Modifier laffichage des messages derreur

La variable de prfrence $ErrorView paramtre le format d'affichage des messages d'erreur


dans Windows PowerShell. Ses valeurs valides sont :
NormalView

Une vue dtaille conue pour la plupart des utilisateurs.

Valeur par dfaut

Comprend une description de l'erreur, le nom de l'objet impliqu dans


l'erreur et des flches (<<<<) qui pointent vers les mots de la commande
qui ont provoqus l'erreur.

CategoryView

Une vue succincte, structure, conue pour les environnements de


production. Le format est :
{Category}: ({TargetName}:{TargetType}):[{Activity}],{Reason}

Voir aussi les exemples de laide en ligne :


Get-Help Preference_Variable

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 17 / 38

Cette possibilit ncessite une construction plus labore du message derreur et implique une
rflexion sur la catgorisation des erreurs de chacun de vos traitements :
} catch {
#$PSCmdlet est une variable automatique cre
#dans la port dune fonction avance.
$PSCmdlet.WriteError(
(New-Object System.Management.Automation.ErrorRecord(
$_.Exception,
"PDFDocumentInfoUriOrPath",
"InvalidOperation",
("{0} : {1}" f $MyInvocation.Mycommand.Name,$_.Exception.Message))
)
)
}
finally {

Le cmdlet Write-Error autorise galement ce type de construction :


$Message="{0} : {1}" f $MyInvocation.Mycommand.Name,$_.Exception.Message
Write-Error -Message $Message `
-Exception $_.Exception `
-Category InvalidOperation `

#Catgorisation Norme, voir le SDK

-TargetObject $MyObject `
-RecommendedAction "Corriger le chemin d'accs." `
-ErrorId "CantWriteLog, Measure-Time" `
-CategoryReason PDFDocumentInfoUriOrPath #Catgorisation personnelle

Pour plus d'informations consultez "Class ErrorCategoryInfo " dans le Kit de dveloppement
logiciel (SDK) Windows PowerShell. Vous trouverez un exemple complet dun tel usage dans le
script Replace-String.ps1.
Comme indiqu dans la page suivante :
http://msdn.microsoft.com/en-us/library/windows/desktop/ms714465%28v=vs.85%29.aspx
pour les erreurs simples, le message affich est celui du champ exception. Pour le remplacer
utilisez la proprit ErrorDetails :
$ErrRec=New-Object System.Management.Automation.ErrorRecord(
$_.Exception,
"PDFDocumentInfoUriOrPath",
"InvalidOperation",
("{0} : {1}" f $MyInvocation.Mycommand.Name,$_.Exception.Message)
)
$ErrRec.ErrorDetails=New-Object System.Management.Automation.ErrorDetails(
"Mon message de remplacement")
$PSCmdlet.WriteError($ErrRec)

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 18 / 38

4.4

Modifier dautres comportements

Pour la version 2 de Powershell, la modification de comportement peut se faire sur les flux
suivants :
dir variable:*preference
Name
Value
-------ConfirmPreference
High
DebugPreference
SilentlyContinue
ErrorActionPreference SilentlyContinue
ProgressPreference
Continue
VerbosePreference
SilentlyContinue
WarningPreference
Continue
WhatIfPreference
False

5 La construction dun gestionnaire dexception


La construction dun gestionnaire dexception ncessite lusage des instructions Try, Catch et
Finally :
Script ou fonction ou ScriptBlock
Try
Dclenchement
dune exception

Code fonctionnel

Catch
Gestion derreurs

5.1

Try

Cette instruction dbute la gestion dexception pour un bloc de code que vous jugez utile de
protger. Chaque dclenchement dexception forcera lexcution du code dans le(s) bloc(s)
Catch ou Finally associ(s). Un bloc Try seul na donc pas de raison dtre et provoquera une
erreur de parsing. Le code en dehors de cette construction ne sera pas protg des exceptions.
Exemple :
Try
{ code dun traitement protger }
Catch
{ code de gestion derreur }

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 19 / 38

Le code protger peut tre constitu dune seule ligne pouvant tre un appel un cmdlet ou
encore un appel une mthode dun objet.
Il reste possible de placer du code en dehors du bloc try :
code sans protection
Try
{ code dun traitement protger }
Catch
{ code de gestion derreur }
suite du code sans protection

Vous seul dcidez des sections de code que vous voulez protger par ce mcanisme.
5.2

Catch

Cette instruction dbute un bloc de code de traitement dun ou plusieurs types dexceptions,
dclenches dans le bloc Try associ. Un bloc Catch seul na pas de raison dtre et provoquera
une erreur de parsing.
Un bloc Try peut tre associ plusieurs blocs Catch. Chaque bloc permettra de traiter (capturer)
un ou plusieurs types dexception.
5.2.1 Accs lobjet Exception
Dans le bloc de code associ linstruction Catch, lobjet exception est accessible via la variable
automatique $_.
5.2.2 Comportement avec une erreur simple
La construction Try/Catch nopre que sur les erreurs bloquantes, cest dire que sur un
dclenchement dexception. Dans lexemple suivant lerreur nest pas prise en charge par le bloc
catch :
$ErrorActionPreference="Continue"
Try {
$process = Get-WmiObject Win32_Process -computername "offline"
Write-host "Instruction suivante"
} Catch [System.Management.Automation.ActionPreferenceStopException]{
write-warning "Erreur gre."
}
Write-host "Suite du script"
Get-WmiObject : Le serveur RPC n'est pas disponible. (Exception de HRESULT : 0x800706BA)
Instruction suivante
Suite du script

Si la variable $ErrorActionPreference est assigne Stop, dans ce cas une erreur dclenchera
une exception du type System.Management.Automation.ActionPreferenceStopException :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 20 / 38

$ErrorActionPreference="Stop"
Try {
$process = Get-WmiObject Win32_Process -computername "offline"
Write-host "Instruction suivante"
} Catch [System.Management.Automation.ActionPreferenceStopException]{
write-warning "Erreur gre."
}
Write-host "Suite du script"
AVERTISSEMENT : Erreur gre.
Suite du script

On peut galement utiliser le paramtre ErrorAction si on souhaite traiter les erreurs au cas par
cas, cest dire sur un cmdlet et pas sur la totalit du bloc de code protg :
$ErrorActionPreference="Continue"
Try {
$process = gwmi Win32_Process computer "offline" ErrorAction Stop
Write-host "Instruction suivante"
} Catch [System.Management.Automation.ActionPreferenceStopException]{
write-warning "Erreur gre."
}
Write-host "Suite du script"
AVERTISSEMENT : Erreur gre.
Suite du script

5.2.3 Une construction viter


Le code suivant est viter :
$ErrorActionPreference="Continue"
Try {
$process = gwmi Win32_Process computer "offline" ErrorAction Stop
Write-host "Instruction suivante"
} Catch {
#traitement dune erreur Stop
write-warning "Traitement de lerreur."
}

Ici ce gestionnaire dexception traitera toutes les exceptions dclenches dans le bloc try. Le
traitement dune exception due une insuffisance de droit ou un manque de mmoire, nest pas
concern par ce gestionnaire.
Vous devez tant que faire se peut traiter prcisment les exceptions dclenches par vos
traitements. Cette approche considre que toutes les exceptions se valent, ce qui est faux.
Cette construction est donc le plus souvent un abus du langage.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 21 / 38

Je vous laisse rflchir sur lutilit et la pertinence de la construction suivante :


$ErrorActionPreference="Continue"
Try {
$process = gwmi Win32_Process computer "offline" ErrorAction Stop
Write-host "Instruction suivante"
} Catch {}
#Suite du code

En consultant le site http://fr.thedailywtf.com/ vous y lirez que tout est possible ;-)
5.2.4 Capture par type dexception
On peut intercepter une exception par son nom de classe, dans ce cas on ordonnera les noms de
classe dexception du plus particulier au plus gnral. Exemple :
$sb={
try {
$i=0 ;

$chemin = "chemin_inexistant"

#5/$i #Dclenche lexcution du bloc Catch "[exception] non spcifi"


[io.directory]::SetCurrentDirectory($chemin)
}
catch [System.IO.DirectoryNotFoundException] {
#catch [System.IO.IOException]
Write-Warning "[exception] $($_.Exception.GetType().FullName)"
}
catch {

Write-Warning "[exception] non spcifi"

finally { "Fin du traitement de try/catch" }


}
&$sb

Si on remplace, le nom de classe System.IO.DirectoryNotFoundException dexception par une


classe anctre :
catch [System.IO.IOException] {

Le code fonctionnera toujours, mais dans ce cas le bloc Catch couvrira les exceptions suivantes :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 22 / 38

Classe

Description

System.IO.DirectoryNotFoundException Exception dclenche lorsqu'une partie d'un fichier ou


d'un rpertoire est introuvable.
System.IO.DriveNotFoundException

Exception dclenche lors d'une tentative d'accs un


lecteur ou partage qui n'est pas disponible.

System.IO.EndOfStreamException

Exception dclenche en cas de tentative de lecture audel de la fin du flux.

System.IO.FileLoadException

Exception dclenche lorsqu'un assembly manag est


trouv mais ne peut pas tre charg.

System.IO.FileNotFoundException

Exception dclenche lors d'une tentative d'accs un


fichier qui n'existe pas sur le disque, choue.

System.IO.PathTooLongException

Exception dclenche lorsqu'un nom de chemin d'accs


ou de fichier est plus long que la longueur maximale
dfinie par le systme.

Qui reprsentent, par dfaut, toutes les classes drives de System.IO.IOException.


Ce qui implique que dans la construction suivante :
catch [System.IO.IOException] { "IOException" }
catch [System.IO.DirectoryNotFoundException] {"Inutile "}

Le second bloc ne sera jamais dclench, car le second type dexception,


DirectoryNotFoundException, sera trait par le premier bloc Catch.
Le parseur renvoie donc une exception sur ce type de construction :
System.IO.DirectoryNotFoundException : Le type d'exception System.IO.DirectoryNotFoundException est
dj gr par un prcdent gestionnaire.

En revanche linverse est possible :


catch [System.IO.DirectoryNotFoundException] {"Directory Not Found "}
catch [System.IO.IOException] { "Autre IOException" }

Car lordre des exceptions, la plus particulire en premier suivi des plus gnrales, est respect.
Enfin, il est possible dassocier plusieurs types dexception un seul bloc catch :
catch [IO.DirectoryNotFoundException],[IO.FileNotFoundException]
{ "Problme de chemin d'accs." }

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 23 / 38

5.2.1 Redclenchement dexception


Pour redclencher une exception, on procdera ainsi :
try {
Write-Host "Initialisation des ressources."
Throw (New-Object System.ApplicationException("Erreur applicative.") )
}
catch {
Write-Warning "Libration des ressources."
Write-Host "`t Erreur ! Redclenche l'exception."
Throw $_
}

Affichera :
Initialisation des ressources.
AVERTISSEMENT : Libration des ressources.
Erreur ! Redclenche l'exception.
throw : Erreur applicative.
Au niveau de ligne : 3 Caractre : 8
+ Throw <<<< (New-Object System.ApplicationException("Erreur applicative.") )
+ CategoryInfo
: OperationStopped: (:) [], ApplicationException
+ FullyQualifiedErrorId : Erreur applicative.

Notez que le contexte de cette exception redclenche restera li au contexte de lexception


dorigine, cest--dire le cas dexception Erreur applicative , et pas celui du bloc o elle est
redclenche. Plus prcisment le contenu de la proprit Invocation restera li au contexte de
lexception dclenche dans le bloc try et pas celui de lexception redclenche dans le bloc
catch.
On utilise ici la construction devant tre vite, la diffrence est quon libre les ressources puis
on renvoie lexception vers les gestionnaires dexception de lappelant qui pourraient la traiter.
Note :
On peut parfois vouloir redclencher une exception en modifiant son message tout en gardant le
type de lexception. Dans ce cas on doit tenir compte des classes dexception daccs priv. Pour
rsoudre ce problme on utilisera la fonction dclare dans le script New-Exception.ps1,
disponible dans les sources.
5.2.2 Gestion dexception dans le pipeline
La gestion des exceptions dans un enchanement dinstructions utilisant le pipeline nest pas
aise raliser, consultez ce post, ainsi que les commentaires pour plus de dtail :
http://powershell.com/cs/blogs/tobias/archive/2010/01/01/cancelling-a-pipeline.aspx
La version 3 de powershell propose lexception interne StopUpstreamCommandsException, voir
cette demande de modification de laccs de cette API :
https://connect.microsoft.com/PowerShell/feedback/details/768650/enable-users-to-stoppipeline-making-stopupstreamcommandsexception-public
Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 24 / 38

5.2.3 Comment dterminer les exceptions capturer


La difficult est de connaitre toutes les exceptions quune mthode peut dclencher, certaines
sont documentes sur le site MSDN. En revanche la documentation des cmdlets Powershell ne
rfrence pas les exceptions pouvant tre dclenches par un cmdlet. Vous devrez donc, laide
de jeux de tests dterminer celles que vous jugerez utile de grer dans vos traitements.
Ce jeux test de validera votre gestion dexception.
Dans un exemple prcdent, on utilise la mthode suivante :
[IO.Directory]::SetCurrentDirectory($chemin)

Pour retrouver les exceptions que cette mthode peut dclencher on consulte le site MSDN :
http://msdn.microsoft.com/fr-fr/library/system.io.directory.setcurrentdirectory%28v=vs.80%29.aspx

Dans la seconde partie du document intitul LaNotionDobjetSousPowerShell.pdf , disponible


dans les sources, vous trouverez quelques informations sur lusage du site MSDN. Je ny ai pas
modifi les recopies dcran, car ce site est rgulirement modifi, mais les principes de
navigation restent identiques. En revanche selon votre version de Powershell, pensez modifier
le framework cibl. Pour la version 2 ciblez le framework 2.0, pour la version 3 le framework 4.0
et pour la version 4.0 le framework 4.5.
Dans le cas o vous ne disposez pas de la documentation des API que vous utilisez, vous pouvez
retrouver les noms des exceptions laide de la fonction Resolve-Error.
Voir aussi cet article :
http://mohundro.com/blog/2009/01/26/finding-the-right-exception-to-throw/

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 25 / 38

5.3

Finally

Cette instruction dbute un bloc de code qui sera excut dans tous les cas, quil y ait eu ou non
une erreur. Son rle est dassurer de lexcution dun code de libration de ressources ou dun
traitement final :
Script ou fonction ou ScriptBlock
Try
Code fonctionnel

Catch
Gestion derreurs
Finally
Code de finalisation
(libration mmoire)

Cest dans ce bloc quon appellera la mthode Dispose() sur des objets ayant des ressources
systme librer ou pour clore des connexions des ressources externes:
try {
$Stream = New-Object System.IO.MemoryStream
$isDisposable=$Stream -is [System.IDisposable]
if ($isDisposable)
{ Write-Warning "L'objet doit tre libr explicitement." }
}
finally
{
if ($Stream -ne $Null)
{
Write-Debug 'Libration des ressources systme de l''objet $Stream.'
$Stream.Dispose()
$Stream=$null
}
}

Notez le test sur le contenu de la variable qui vite de dclencher une erreur si celui-ci nest pas
renseign.
On ne peut associer quune seule instruction Finally une instruction Try.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 26 / 38

Un bloc Finally seul na pas de raison dtre et provoquera une erreur de parsing.
La construction suivante est autorise :
Script ou fonction ou ScriptBlock
Try
Code fonctionnel

Finally
Code de finalisation
(libration mmoire)

Elle permet dimplmenter un code de finalisation tout en laissant au code appelant la


responsabilit de traiter les exceptions que votre traitement pourrait dclencher.
On peut donc dcider de ne pas traiter localement lexception, mais de la propager.
Voir aussi le fichier daide :
Get-help about_Try_Catch_Finally

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 27 / 38

5.4

Propagation des exceptions imprvues

Nous avons vu prcdemment quune exception dclenche dans un bloc de code protg par
linstruction Try tait gre dans le bloc Catch associ, mais si celui-ci ne gre pas le type de
cette exception (sous rserve de respecter le principe de codage nonc dans la chapitre Une
construction viter) le mcanisme dexception la propage au bloc appelant et ainsi de suite
jusqu trouver un gestionnaire dexception pouvant la traiter :
Code appelant

Try

Script ou fonction ou ScriptBlock


Try
Dclenchement
dune exception

Code fonctionnel

Catch
Gestion derreurs

Propagation
de lexception

Catch
Gestion derreurs

Sil nexiste aucun gestionnaire dexception, le host tant le niveau le plus haut, cest dans celuici que lexception sera affiche afin de nous informer dune erreur fatale. Sous rserve que le
host dispose dune zone daffichage, ce qui nest par exemple pas le cas du host dOrchestrator
2012.
Ainsi nous serons averti de lexistence dune erreur corriger, qui peut tre une ressource
ncessaire mettre disposition (prrequis), par exemple dmarrer un service ou une VM
hbergeant un serveur, utiliser un compte avec suffisamment de droits, etc.
Note :
En cas de dclenchement dune exception lors de lexcution dun script Powershell excut
dans un processus externe, Powershell renverra un code retour (%ErrorLevel%) gal 1.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 28 / 38

5.5

Linstruction Trap

Linstruction Trap est quivalente aux instructions Try-Catch-Finally, ayant une prfrence pour
ces dernires je ne la traiterais pas ici.
Sur le sujet vous pouvez consulter ces liens :
http://blogs.msdn.com/b/powershell/archive/2009/06/17/traps-vs-try-catch.aspx
http://blogs.msdn.com/b/powershell/archive/2006/12/29/documenting-trap-and-throw.aspx
http://blogs.msdn.com/b/powershell/archive/2006/04/25/583234.aspx
Selon les cas, elle peut faciliter un mcanisme de reprise sur erreur.

6 Paramtres communs de cmdlet ou de fonction lis aux erreurs


Chaque cmdlet peut modifier le fonctionnement par dfaut des erreurs laide du paramtre
commun ErrorAction. Quant au paramtre commun ErrorVariable il permet de rcuprer les
erreurs dclenches par le cmdlet ou la fonction et seulement les siennes.
6.1

ErrorAction

Ce paramtre dtermine comment l'applet de commande rpond une erreur en remplaant la


valeur de la variable $ErrorActionPreference pour la commande actuelle. Ses valeurs valides
sont les mmes que celles de la variable de prfrence $ErrorActionPreference.
Notez que la version 3 de Powershell autorise pour ce paramtre une valeur
supplmentaire nomme Ignore. Cette valeur indique que les erreurs ne seront pas affiches ni
ajoutes la collection $Error
En rappel du principe que lerreur est humaine, voir le bug suivant :
http://connect.microsoft.com/PowerShell/feedback/details/763621/erroraction-ignore-is-brokenfor-advanced-functions
6.2

ErrorVariable

Ce paramtre mmorise, dans le nom de variable spcifie ainsi que dans la variable automatique
$Error, les messages d'erreur dclenchs par un cmdlet.
Par dfaut, les nouveaux messages d'erreur remplacent ceux dj stocks dans la variable. Pour
ajouter le message d'erreur au contenu de la variable, saisissez un signe plus (+) avant le nom de
variable.
Par exemple, la commande suivante cre la variable $MyErrors, puis y stocke toutes les erreurs :
get-process -id 6 -ErrorVariable MyErrors

La commande suivante complte la variable $MyErrors avec les nouvelles erreurs :


get-process -id 2 -ErrorVariable +MyErrors

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 29 / 38

6.3

WarningVariable

Ce paramtre mmorise, dans le nom de variable spcifie, les messages d'avertissement gnrs
par un cmdlet. Une fois ce paramtre prcis les avertissements ne sont plus affichs :
function Test-Warning {
[CmdletBinding()]
param()
Write-Warning "Avertissement !"
}
$WarningActionPreference="Continue"
Remove-Variable MesWarnings -ErrorAction SilentlyContinue
Test-Warning -WarningVariable MesWarnings
$MesWarnings
Avertissement !

Un autre exemple li Office 365 :


Import-Module MSOnline
Connect-MsolService -credential $Credentials WarningVariable MsolWarn
$MsolWarn

Ici la variable MsolWarn peut contenir un avertissement concernant la disponibilit dune


nouvelle version du module MSOnline.
Ou encore sous Exchange :
$MBStat=Get-MailboxStatistics -Identity $Id -WarningVariable gmbxsWarning
-WarningAction stop

Si la bote mail cible ne contient pas dlment, le cmdlet Get-MailboxStatistics ne renvoie pas
dinformation, mais un warning. Selon le traitement on peut choisir de gnrer une erreur
bloquante laide du paramtre WarningAction. Lexception dclenche sera du type
System.Management.Automation.ActionPreferenceStopException
6.4

Comment implmenter ce type de variable ?

Vous trouverez une implmentation sur le lien suivant :


http://powershell-scripting.com/index.php?option=com_joomlaboard&Itemid=76&func=view&id=15033&catid=14

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 30 / 38

7 Gestionnaire dexception globale


Dans le chapitre Propagation des exceptions imprvues nous avons vu quune exception peut
ne pas tre gre dans le code, ce qui stoppera le script en cours. La mise en place dun
mcanisme de mmorisation de ce type derreur sera trs utile aux personnes du support.
La console Powershell est excute dans un domaine dapplication dotnet, qui propose un
vnement ddi cette gestion :
[System.AppDomain]::CurrentDomain|gm -MemberType Event
TypeName: System.AppDomain
Name
MemberType Definition
---------------------AssemblyLoad
Event
System.AssemblyLoadEventHandler

UnhandledException
Event
System.UnhandledExceptionEventHandler

Je prfre toutefois crer une fonction implmentant un tel gestionnaire.


La fonction Invoke-CommandWithUnhandledExceptions, disponible dans les sources, propose
une implmentation dun tel mcanisme. Elle excute du code dans un bloc try/catch et srialise
la collection derreur dans un fichier XML. Ce qui permet de la recharger ultrieurement dans
une variable. Sa vocation nest pas de librer des resources en cas derreur, mais denregistrer
lhistorique des erreurs pour un traitement donn.
La fonction Get-LastError se charge de cette opration, ce qui implique de crer pour chacun de
vos traitements un rpertoire de logs ddi.
Pour lexemple suivant, les scripts de dmonstration sont situs dans le rpertoire C:\Temp :
#Modifier avec votre rpertoire contenant les sources
Cd C:\Temp
. .\Test-InvokeCommandWithUnhandledExceptions.ps1

Le rsultat dexcution affichera ceci :

En lui prcisant le chemin de log C:\Temp\Logs la fonction Get-LastError renvoie la dernire


erreur gnre par le script de test :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 31 / 38

Notez que la fonction Get-LastError peut renvoyer une collection derreur, lhistorique des
erreurs donc. Le premier lment de la collection contiendra des informations sur lerreur ayant
arrte le script.

8 Gnrer des classes dexception


Powershell ne proposant pas dinstruction de cration de classe, lusage de linstruction throw
sen trouve limit. Il reste possible dutiliser certaines exceptions types existantes ou den crer
de nouvelles spcifiques un traitement.
8.1

Type dexception utilisable

Voici quelques exceptions pouvant tre utilises dans vos scripts :


System.ApplicationException

Cette exception est dclenche lorsquune erreur


fonctionnelle survient dans votre application ou votre script.

System.ArgumentException

Est dclenche lorsquun des arguments dune mthode ou


une fonction est invalide.

System.NullReferenceException

Est dclenche lorsquon adresse un objet ayant la valeur


null.

System.NotImplementedException

Est dclenche lorsquon appelle une mthode ou fonction


qui nest pas implment.

System.IndexOutOfRangeException Est dclenche lorsquon accde un lment en dehors des


limites dun tableau.
Il en existe dautres, mais leur usage sous Powershell apporterait une confusion. Par exemple, on
peut tre tent dutiliser la classe System.OperationCanceledException, mais celle-ci est ddie
la gestion des threads
8.2

Crer ses propres exceptions

Pour crer des exceptions spcifiques, il nous faut gnrer le code C# de dclaration de la classe
puis le compiler laide du cmdlet Add-Type.
On drivera nos classes dexception partir de la classe System.ApplicationException et chaque
classe dfinira les trois constructeurs suivant :
Nom

Description

Exception ()

Initialise une nouvelle instance de la classe Exception.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 32 / 38

Exception (String)

Initialise une nouvelle instance de la classe Exception avec un


message d'erreur spcifi..

Exception (String, Exception) Initialise une nouvelle instance de la classe Exception avec un
message d'erreur spcifi et une rfrence l'exception interne
qui est l'origine de cette exception.
La rgle de nommage prconise est de postfixer le nom de la classe avec Exception :
#code C#

public class MonTraitementException : System.ApplicationException {}

Vous trouverez dans les sources la fonction New-ExceptionClass ddie la cration dexception
personnalis.
Lexcution de linstruction suivante :
New-ExceptionClass PsionicException,Posh4LogException passthru

Gnre uniquement du code C#:


[Serializable]
public class PsionicException : System.ApplicationException
{
public PsionicException()
{}
public PsionicException(string message) : base(message)
{}
public PsionicException(string message, Exception innerException)
: base(message, innerException)
{}
}
[Serializable]
public class Posh4LogException : System.ApplicationException
{
public Posh4LogException ()
{}
public Posh4LogException (string message) : base(message)
{}
public Posh4LogException (string message, Exception innerException)
: base(message, innerException)
{}
}

Celle-ci gnre le code puis compile dynamiquement lassembly


New-ExceptionClass PsionicException,Posh4LogException
$Exception=New-Object Posh4LogException "Appender inconnu."
$Exception|Select-Object *
Message
: Appender inconnu.
Data
: {}
InnerException :
TargetSite :
StackTrace :
HelpLink
:
Source
:

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 33 / 38

Linstruction suivante, utilise une hashtable dclarant des classes dexception au sein dun
espace de nom :
$NameSpaces=@{
'Module.Posh4Log'=@('GetAppenderException');
'Module.Validation'=@('UserDataException','ADAttributException')
}
New-ExceptionClass $NameSpaces
$Message="Le champ MemberGroup doit tre renseign."
$Exception=New-Object Module.Validation.UserDataException $Message

Ces objets exceptions seront utiliss soit avec le cmdlet Write-Error soit avec linstruction
Throw :
Throw $Exception

9 Quelques oprations rcurrentes


9.1

Tester si une erreur a eu lieu

La variable automatique $? contient le rsultat dexcution de la dernire opration, savoir si


elle a russie ou pas :
$ErrorActionPreference='Continue'
$Error.Clear()
xcopy.exe Inconnu.txt Nouveau.txt
Fichier introuvable - Inconnu.txt
0 fichier(s) copi(s)
if (-not $?)
{
Write-host "Dernire instruction en erreur."
Write-host "Code de sortie : $LastExitCode"
}
Dernire instruction en erreur.
Code de sortie : 4

9.2

Dterminer le retour dexcution dune commande

Quant la variable automatique $LastExitCode elle contient le code de sortie du dernier


programme excut. Dans ce cas la collection derreur $Error nest pas renseigne, car le
programme est excut en dehors du mcanisme derreur de Powershell.
Notez que la variable automatique $LastExitCode nexiste pas au dmarrage dune session et
quelle nest modifie que lors de lappel dun programme externe.
Autres exemples :
Cmd /c exit 0
"Exccution : $?"

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 34 / 38

"Code de sortie : $LastExitCode"


Exccution : True
Code de sortie : 0
Cmd /c exit 127
"Exccution : $?"
"Code de sortie : $LastExitCode"
Exccution : False
Code de sortie : 127
Dir
$?
True
$LASTEXITCODE
127 #Contient le dernier code retour dexcution dun programme externe

9.3

Redirection derreur

Pour prendre en compte les erreurs renvoyes par un programme externe, sil les met dans le
flux standard stderr, on utilisera la redirection suivante :
$Error.Clear()
xcopy.exe Inconnu.txt Nouveau.txt 2>&1
0 fichier(s) copi(s)
xcopy.exe : Fichier introuvable - Inconnu.txt

Avec cette instruction Powershell se connecte au flux derreur du programme externe et redirige
les erreurs de ce programme dans son flux derreur spcifique. On gnre donc des erreurs
Powershell tout en renseignant la collection $Error.
Notez que dans ce cas le type est RemoteException :
$Error[0]|select *
PSMessageDetails :
Exception
: System.Management.Automation.RemoteException: Fichier introuvable - Inconnu.txt
TargetObject
: Fichier introuvable - Inconnu.txt
CategoryInfo
: NotSpecified: (Fichier introuvable - Inconnu.txt:String) [], RemoteException
FullyQualifiedErrorId : NativeCommandError
ErrorDetails
:
InvocationInfo
: System.Management.Automation.InvocationInfo
PipelineIterationInfo : {0, 0}

Celle-ci redirige le flux derreur vers $null :


xcopy.exe Inconnu.txt Nouveau.txt 2>$null
0 fichier(s) copi(s)

La collection $Error est galement renseigne, mais il ny a plus daffichage sur la console. Le
paramtrage de $ErrorActionPreference influencera ce comportement.
Cette construction est galement possible :
$Error.Clear()
xcopy.exe Inconnu.txt Nouveau.txt 2> C:\Temp\Erreur.txt|

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 35 / 38

Foreach-object {write-host $_ -fore green}


0 fichier(s) copi(s)
Type C:\Temp\Erreur.txt
xcopy.exe : Fichier introuvable - Inconnu.txt
Au niveau de ligne : 1 Caractre : 10
+ xcopy.exe <<<< Inconnu.txt Nouveau.txt 2> C:\Temp\Erreur.txt|
+ CategoryInfo
: NotSpecified: (Fichier introuvable - Inconnu.txt:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

Voir aussi le chapitre "Redirection Operators" de laide en ligne :


Get-Help about_operator

Enfin une application dotnet dclenchant une exception imprvue, ne renseignera pas la
collection $Error. Le programme de test ErrorOut.exe, prsent dans les sources, dclenche une
telle exception :
$Error.Clear()
.\ErrorOut.exe

$Error.Count
0

Pour trapper cette exception sous Powershell on doit utiliser la redirection :


$Error.Clear()
.\ErrorOut.exe 2>&1
$Error.Count
.\ErrorOut.exe :
Au niveau de ligne : 1 Caractre : 15
+ .\ErrorOut.exe <<<< 2>&1
+ CategoryInfo
: NotSpecified: (:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Exception non gre :
System.DivideByZeroException: Tentative de division par zro.
ErrorOut.ErrOut.Main()
$Error.Count
4

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 36 / 38

9.4

Flux standard

Les programmes de type console nommes program.exe et program2.exe, utilisent les flux
standards du systme stderr et stdout :
#code C#
Console.Error.WriteLine("Emit sur le flux d'erreur (stderr)");
Console.Out.WriteLine("Emit sur le flux de sortie (stdout)");

Rsultat dexcution :
cd "VotreRpertoireDeDemo"
$Error.Clear()
.\program.exe 1 > "C:\Temp\Erreurs.txt"
Emit sur le flux d'erreur (stderr)
Tentative de division par zro.
type "C:\Temp\Erreurs.txt"
Emit sur le flux de sortie (stdout)
$error.Count #n'est pas renseigne
0
.\program.exe 2>&1
Emit sur le flux de sortie (stdout)
Au niveau de ligne : 1 Caractre : 14
+ .\program.exe <<<< 2>&1
+ CategoryInfo
: NotSpecified: (Emit sur le flux d'erreur (stderr):String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Tentative de division par zro.
$Error.Count
2

Program.exe utilise la mthode WriteLine, program2.exe la mthode Write. Lusage de lune ou


de lautre influence le nombre derreur rcupr par le mcanisme de redirection des erreurs sous
Powershell.
Vous pouvez galement consultez ce poste :
http://powershell-scripting.com/index.php?option=com_joomlaboard&Itemid=76&func=view&id=12899&catid=14

9.4.1 Les nouveaux flux sous Powershell version 3


On peut dsormais rediriger la plupart des flux :
*
1
2
3
4
5

All output
Success output
Errors
Warning messages
Verbose output
Debug messages
Do-Something 3> warning.txt # Writes warning output to warning.txt
Do-Something 4>> verbose.txt # Appends verbose.txt with the verbose output
Do-Something 5>&1 # Writes debug output to the output stream

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 37 / 38

Do-Something *> out.txt # Redirects all streams (output, error, warning,


verbose, and debug) to out.txt

Pour le dtail consultez laide en ligne :


Get-Help About_Redirection.txt

Voir galement dans les sources le script dexemple Test-Redirection.ps1.


9.5

Proprit de formatage

Il existe une proprit nomme WriteErrorStream, li au formatage dun rsultat dinstruction,


Vous trouverez le dtail dans le post suivant :
http://www.beefycode.com/post/Formatting-Individual-PowerShell-Outputs-as-Errors.aspx

10 Conclusion
Au travers de ces pages vous avez pu constater que la gestion derreur est un sujet relativement
simple, mais que son implmentation sous Powershell ncessite de connaitre les nombreux
comportements et les nombreuses possibilits offertes. Nhsitez pas consulter rgulirement le
site MSConnect, car vous pourriez tre amen contourner des bugs du runtime Powershell.
Faute de temps, je nai pas trait la gestion des erreurs lies aux jobs (remoting), un prochain
chapitre peut-tre.
Les tests tant une tape prliminaire la gestion derreur et le debug de script ltape suivante,
vous trouverez de nombreuses ressources sur le net pour aborder ces sujets.
Enfin souvenez-vous que nous avons le droit de faire des erreurs, mais que nous devons tout
faire pour ne pas les reproduire.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux.

Page 38 / 38