Vous êtes sur la page 1sur 67

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

Page 1 / 67
PowerShell version 2 :
Les fonctions avances.
Par Laurent Dardenne, le 13 mars 2010.



Niveau


La version 2 de PowerShell apporte de nombreuses volutions, lune concerne
lcriture de cmdlet en code natif laide de fonctions dites avances utilisant
diffrents types dattributs. Dans le texte suivant je vous propose dtudier la
cration de cmdlets sans utiliser de langage compil dotnet.

Une bonne connaissance des principes de base de PowerShell, notamment celui du
pipeline, du fonctionnement des cmdlets et des classes dotnet, facilitera la lecture
de ce tutoriel qui est tout de mme orient dveloppeur. Difficile de faire
autrement sur un tel sujet, mais cela reste un tutoriel sur le scripting avanc sous
PowerShell.
Merci Thomas Garcia pour sa relecture et ses corrections orthographiques.

Les fichiers sources :
ftp://ftp-developpez.com/laurent-dardenne/articles/Windows/PowerShell/Les-fonctions-et-
scripts-avancees-sous-PowerShell-version-2/fichiers/Les-fonctions-et-scripts-avancees-sous-
PowerShell-version-2.zip

Test avec PowerShell V2 sous Windows XP sp3.
Site de lauteur : http://laurent-dardenne.developpez.com/

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 2 / 67
Chapitres

1 QUELLES SONT LES AVANCEES ?.............................................................................................................4
1.1 PRINCIPE DUN ATTRIBUT............................................................................................................................5
1.2 LES TYPES DATTRIBUT DE PARAMETRE ......................................................................................................5
1.2.1 Attribut Alias..........................................................................................................................................5
1.2.2 Attributs de validation de paramtres....................................................................................................6
1.2.3 Attribut Parameter.................................................................................................................................6
1.3 DECLARER UN ATTRIBUT.............................................................................................................................6
2 LIAISON DE PARAMETRES .........................................................................................................................8
2.1 CONVENTION DE NOMMAGE DE PARAMETRES...........................................................................................10
3 LA GESTION DU PIPELINE ........................................................................................................................11
3.1 DIFFERENCES ENTRE LA VERSION 1 ET LA VERSION 2................................................................................12
4 LES ARGUMENTS DE LATTRIBUT PARAMETER ..............................................................................16
4.1 MANDATORY.............................................................................................................................................16
4.2 POSITION...................................................................................................................................................16
4.3 HELPMESSAGE..........................................................................................................................................17
4.4 VALUEFROMPIPELINE...............................................................................................................................17
4.5 VALUEFROMPIPELINEBYPROPERTYNAME ...............................................................................................17
4.6 VALUEFROMREMAININGARGUMENTS......................................................................................................21
4.7 PARAMETERSETNAME ..............................................................................................................................21
4.7.1 Validit des jeux de paramtres...........................................................................................................23
4.7.2 Lattribut OutputType..........................................................................................................................25
5 LES ATTRIBUTS DE VALIDATION...........................................................................................................26
5.1 ALLOWNULL.............................................................................................................................................28
5.2 VALIDATENOTNULL .................................................................................................................................28
5.3 ALLOWEMPTYSTRING...............................................................................................................................29
5.4 VALIDATENOTNULLOREMPTY.................................................................................................................29
5.5 ALLOWEMPTYCOLLECTION ......................................................................................................................29
5.6 VALIDATECOUNT......................................................................................................................................30
5.7 VALIDATELENGTH....................................................................................................................................30
5.8 VALIDATEPATTERN...................................................................................................................................31
5.9 VALIDATERANGE......................................................................................................................................31
5.10 VALIDATESET ...........................................................................................................................................31
5.11 VALIDATESCRIPT......................................................................................................................................32
5.11.1 Cration de rgles de validation.....................................................................................................33
5.11.2 Usage de fonction de validation dans un module............................................................................34
5.12 DIFFERENCES DE COMPORTEMENT ENTRE UNE FONCTION AVANCEE ET UN CMDLET .................................36
6 CREATION DE PARAMETRES DYNAMIQUES ......................................................................................36
7 LA VARIABLE AUTOMATIQUE PSCMDLET.........................................................................................42
7.1 GESTION DES EXCEPTIONS.........................................................................................................................43
7.2 LA VARIABLE ERRORVIEW........................................................................................................................45
7.3 PROPOS DU BLOC END............................................................................................................................45
8 LES ARGUMENTS DE LATTRIBUT CMDLETBINDING.....................................................................46
8.1 SUPPORTSSHOULDPROCESS ......................................................................................................................46
8.1.1 propos des capacits des providers..................................................................................................47
8.1.2 La mthode ShouldContinue................................................................................................................48

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 3 / 67
8.2 CONFIRMIMPACT.......................................................................................................................................50
8.2.1 La variable $ConfirmPreference .........................................................................................................50
8.2.2 La variable $WhatIfPreference............................................................................................................51
8.3 SUPPORTSTRANSACTIONS .........................................................................................................................52
8.4 DEFAULTPARAMETERSETNAME ...............................................................................................................52
9 ACCEDER AUX DETAILS DUNE COMMANDE.....................................................................................52
9.1 ACCEDER AUX INFORMATIONS DUNE FONCTION ......................................................................................52
9.2 ACCEDER AUX INFORMATIONS DUN CMDLET...........................................................................................55
9.3 ACCEDER AUX INFORMATIONS DUN FICHIER SCRIPT ................................................................................56
9.4 ACCEDER AUX INFORMATIONS DUN MODULE...........................................................................................56
9.5 UNE APPROCHE DU SCRIPTING BASEE SUR DES PLUG-INS...........................................................................57
10 PROXY DE CMDLET ....................................................................................................................................57
10.1 STEPPABLE PIPELINES ...............................................................................................................................59
10.1.1 Bloc Begin.......................................................................................................................................59
10.1.2 Bloc Process....................................................................................................................................60
10.1.3 Bloc End..........................................................................................................................................60
10.2 GESTION DES ERREURS..............................................................................................................................61
10.3 SUPPRESSION DE PARAMETRES..................................................................................................................62
10.4 AJOUT DE PARAMETRES ............................................................................................................................62
11 SCRIPTBLOCK ET ATTRIBUTS ................................................................................................................63
12 CONSTRUIRE LAIDE EN LIGNE..............................................................................................................64
12.1 CONSTRUIRE UN FICHIER DAIDE LOCALISE AU FORMAT MAML..............................................................64
13 LIENS................................................................................................................................................................66
14 CONCLUSION.................................................................................................................................................67

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 4 / 67

1 Quelles sont les avances ?
Les fonctions et scripts dits avancs sont des fonctions ou des scripts autorisant lusage
dattributs comme on en utilise dans les dclarations de cmdlets cods avec un langage dotnet
compil. Ainsi, on peut nativement placer des rgles de validation et des contraintes sur tout ou
partie des paramtres. Nous verrons galement que certains amliorent la prise en charge des
valeurs de paramtres provenant du pipeline.
Avec cette version il est dsormais possible de grer tous les paramtres communs (Whatif,
ErrorAction,) sans avoir coder une seule ligne de code, ou encore dintgrer laide dans le
code source des fonctions ou des scripts. Elle permet galement de crer des proxys de cmdlet et
dorganiser votre code laide de module.
Mais commenons par le commencement et avant daller plus loin voyons les termes de
paramtre et dargument.
Pour linstruction :
Get-ChildItem -Path C:\Temp Recurse
-Path est un paramtre et C:\temp son argument. Recurse est un switch qui ne ncessite pas
dargument.
Le runtime PowerShell, au travers des attributs, nous dcharge dune grande partie de la gestion
des paramtres dun script ou dune fonction, lobjectif tant de proposer un comportement
semblable celui dun cmdlet tout en facilitant lcriture du code.
A lorigine lusage de ces attributs est de contrler les paramtres dun cmdlet cod dans un
langage dotnet.
Un exemple dutilisation en C# :
[Parameter(Position = 0)]
public string Name
{
get { return processName; }
set { processName = value; }
}
private string processName;
Ici on prcise que le paramtre Name se trouve en position zro. Ainsi, lappel suivant ne
ncessite pas de prciser le nom de largument :
MonCmdlet Name "Explorer" Count 1
#devient
MonCmdlet "Explorer" Count 1
La version 2 de PowerShell ne propose pas de crer des attributs comme en C#, mais dutiliser
ceux dj disponibles pour les cmdlets C#. Lquipe de PowerShell a donc ajout quelques mots-
cls spcifiques au contexte de dclaration dune fonction ou dun script.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 5 / 67
1.1 Principe dun attribut
Un attribut associe une ou plusieurs informations un lment du langage. Sous PowerShell
seuls les paramtres dune fonction, dun script ou dun Scriptblock sont concerns par les
attributs. Leur prsence indique au moteur PowerShell de modifier la gestion de ces paramtres,
cest lui qui appliquera les nouveaux comportements prciss par les attributs que vous avez
placs sur chacun dentre eux.
Un attribut peut tre considr comme une mtadonne, c'est--dire une information sur une
information. Voyons un exemple :
Param (
[alias("CN")] [alias("CN")] [alias("CN")] [alias("CN")]
$ComputerName
)
On dclare un alias sur le paramtre $ComputerName. Il sera donc possible de le rfrencer, lors
dun appel de cette fonction, par son nom dorigine ou par son nom dalias.
Lattribut alias porte sur le paramtre $ComputerName. La dclaration de lattribut prcde celle
du nom de paramtre. Sa syntaxe est la suivante :
alias est le nom de lattribut,
("CN") est un argument renseignant une proprit de cet attribut. Celui-ci peut en dclarer
plusieurs, dans ce cas on les sparera par des virgules.
Le tout est dclar entre crochets [ ].
La syntaxe dun attribut est donc celle-ci :
[ [[ [NomAttribut(liste darguments)] ]] ]
Nom_de_paramtre_de_la_fonction
Ce qui permet les appels suivants :
MaFonctionAvance -ComputerName "Server1"
#ou
MaFonctionAvance Cn "Server1"
On peut galement considrer un attribut comme tant un paramtrage, on paramtre du code, ici
un paramtre, et pas un traitement. Ce paramtrage est destin au compilateur du code source
PowerShell.
1.2 Les types dattribut de paramtre
Il existe trois types dattributs portant sur un paramtre :
1.2.1 Attribut Alias
L'attribut Alias spcifie un autre nom pour le paramtre. Le nombre d'alias qui peuvent tre
affects un paramtre est illimit.
Attention les noms dalias suivants sont rservs : vb, db, ea, ev, ov, et ob.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 6 / 67
1.2.2 Attributs de validation de paramtres
Ces attributs de validation de paramtres dfinissent la faon dont le runtime Windows
PowerShell valide les arguments des fonctions avances.
1.2.3 Attribut Parameter
L'attribut Parameter est utilis pour dclarer un paramtre de la fonction. Cet attribut comporte
des arguments nomms utiliss pour dfinir les caractristiques du paramtre, par exemple pour
savoir s'il est obligatoire ou optionnel.

Il existe galement lattribut [CmdletBinding()] qui lui porte sur le comportement dune
fonction ou dun script, nous laborderons par la suite.
1.3 Dclarer un attribut
On dclare un attribut au sein de la clause Param :
Function FcntAvance{
Param (
[Parameter(Position=0)]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count reste=$args"
}
La dclaration suivante est autorise :
Function FcntAvance(
[Parameter(Position=0)]
$NomParam,
$Count){
Write-host "`$NomParam=$NomParam `t `$Count=$Count reste=$args"
}
Cette fonction dclare le paramtre $NomParam en prcisant quil est en premire position.
Testons notre fonction :
FcntAvance "Deux"
$NomParam=Deux $Count= reste=
FcntAvance "Deux" 2
Le second appel provoque lerreur suivante :
FcntAvance : Impossible de trouver un paramtre positionnel acceptant l'argument 2 .
Ceci est du au fait que la prsence dun paramtre positionnel nous contraint prciser le nom de
ceux qui nont pas dindication de position, par exemple $count :
FcntAvance "Deux" -count 2
$NomParam=Deux $Count=2 reste=

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 7 / 67
Si on ajoute un paramtre anonyme , rcupr dhabitude dans la variable $args, cela
provoque la mme erreur :
FcntAvance "Deux" -count 2 3
FcntAvance : Impossible de trouver un paramtre positionnel acceptant l'argument 3 .
Modifions lattribut :
Function FcntAvance{
Param (
[Parameter(Mandatory=$True)]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count reste=$args"}
Cette fois on impose la prsence dun argument pour le paramtre $NomParam, testons cette
modification :
FcntAvance "Deux" 2
$NomParam=Deux $Count=2 reste=
FcntAvance "Deux" 2 3
FcntAvance : Impossible de trouver un paramtre positionnel acceptant l'argument 3 .
FcntAvance count 3
applet de commande FcntAvance la position 1 du pipeline de la commande
Fournissez des valeurs pour les paramtres suivants :
NomParam:
On constate que
- le premier appel ne ncessite plus de prciser le nom du second paramtre,
- le second appel provoque toujours une erreur,
- le troisime appel force PowerShell nous demander une valeur pour le premier
paramtre, cest le comportement attendu.
Enfin pour lappel suivant PowerShell rorganise la liaison des paramtres :
FcntAvance -count 4 deux
$NomParam=deux $Count=4 reste=
On voit bien que la prsence ou labsence dattribut positionnel modifie cette liaison (Binding
Parameters).
Un autre point concernant la dclaration dattributs : on peut prciser plusieurs types dattribut
sur chaque paramtre, mais lattribut Parameter doit tre unique :
Function FcntAvance{
Param (
[Parameter(Mandatory=$True)]
[Parameter(Position=0)]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 8 / 67
FcntAvance deux 4
Le paramtre NomParam est dclar plusieurs fois dans le jeu de paramtres __AllParameterSets .
Le code prcdent provoque une erreur, car lattribut Parameter est prcis deux fois, on doit
dclarer plusieurs arguments de la manire suivante :
Function FcntAvance{
Param (
[Parameter(Mandatory=$True, Position=0)]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count"}
2 Liaison de paramtres
Nous avons vu prcdemment que la prsence dattribut positionnel modifie la liaison des
paramtres. La liaison est lopration daffectation dune valeur un paramtre, prcde
dautres oprations, telle que la validation des rgles portes par les possibles attributs du
paramtre.
Il existe un autre attribut qui modifie cette liaison, lattribut [CmdletBinding()] qui doit tre
imprativement coupl avec une instruction Param. Cet attribut prcise que notre fonction/script
utilisera la mme liaison de paramtre quun cmdlet, c'est--dire que les paramtres inconnus et
les arguments positionnels sans paramtre positionnel correspondant entranent l'chec de la
liaison des paramtres en provoquant une exception. Cet attribut autorise dautres traitements
que nous verrons par la suite.
La prsence dans une fonction ou un script dun attribut Parameter ou CmdletBinding fait que
PowerShell dclare une variable automatique nomme $PSCmdlet que nous aborderons plus
avant dans ce tutoriel.
Sachez quune fonction/script dclarant cet attribut n'utilise pas la variable $args. Cette variable
est toujours prsente dans le provider variable:, mais elle rfrence celle dclare dans la porte
parente. Le test suivant vous permettra de visualiser ce point :
Function FcntTest{
Function FcntAvance{
#[CmdletBinding()]
Param (
# [Parameter(ValueFromPipeline = $true)]
$NomParam,
$Count)
Write-warning "Dans FcntAvance "
if ($myinvocation.MyCommand.CmdletBinding)
{Write-Host 'CmdletBinding dtect.' -fore Green}
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
dir variable:args
if (test-path Variable:PSCmdlet)

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 9 / 67
{
Write-Host '$args inexistant localement' -fore Green
Write-Host "`$PSCmdlet dclar dans $($pscmdlet.CommandRuntime)"`
-fore Green
}
}

Function FcntImbrique {
[CmdletBinding()]
Param ([Alias("Test")]
$ParamTest)

Write-warning "FcntImbrique : `$ParamTest=$ParamTest"
if ($myinvocation.MyCommand.CmdletBinding)
{Write-Host 'CmdletBinding dtect.' -fore Green}
dir variable:args
if (test-path Variable:PSCmdlet)
{Write-Host 'Liaison modifie.' -fore Green}
FcntAvance deux 10 # 7 "test"
}

Write-warning "Dans FcntTest"
if ($myinvocation.MyCommand.CmdletBinding)
{Write-Host 'CmdletBinding dtect.' -fore Green}
dir variable:args
FcntImbrique -Test un # 2 34
}
FcntTest un 5 -4 test
Lajout ou la suppression des commentaires, sur tout ou partie des lignes prcdentes dclarant
un attribut, modifiera le rsultat. Je vous laisse tester les diffrents cas.
Il est possible de tracer le traitement de liaison de la manire suivante :
Trace-Command -name ParameterBinding {FcntAvance "Deux" 2 3} pshost
Notez quil existe une variable automatique nomme $PSBoundParameters, pointant sur
$MyInvocation.BoundParameters, contenant la liste des paramtres lis :
Function Test-UnBoundArguments
{
param([String] $Name,[int]$Nombre=3,[switch] $Stop)
$OutValue = $null
if ($MyInvocation.BoundParameters.TryGetValue('Nombre', [ref]$OutValue))
{
if ($OutValue -eq $null)

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 10 / 67
{Write-Warning "Le paramtre Nombre prend la valeur `$null."}
else
{Write-Warning "Le paramtre Nombre est prcis et prend la valeur $OutValue."}
}
else
{
Write-Warning "Le paramtre Nombre n'est pas prcis, mais prend la valeur par dfaut."
}
#if ($PSBoundParameters.ContainsKey('Nombre'))
# { write-host 'X Bound.' }
"Nombre =$Nombre"
}

Test-UnBoundArguments
Test-UnBoundArguments -name "Test"
Test-UnBoundArguments "Test"
Test-UnBoundArguments "Test" 5
Test-UnBoundArguments "Test" $null
Test-UnBoundArguments "Test" -nombre $null
Test-UnBoundArguments "Test" -nombre
Sur le sujet vous pouvez galement consulter le schma suivant, Cmdlet Processing Lifecycle :
http://msdn.microsoft.com/en-us/library/ms714429(VS.85).aspx

Si, dans la dclaration dune fonction, vous ne prcisez pas la clause Param, vous devez prciser
lattribut [CmdletBinding()] de la manire suivante :
Function FcntAvance(
[cmdletbinding()]
[Parameter(Position=0)]
$NomParam,
$Count){
#[cmdletbinding()] -> erreur
Write-host "`$NomParam=$NomParam `t `$Count=$Count reste=$args"
}
Sinon la variable automatique nomme $PSCmdlet ne sera pas cre.
2.1 Convention de nommage de Paramtres
Comme pour le nommage des cmdlets, Microsoft recommande de suivre les prconisations
portant sur le nommage des noms de paramtres. Lobjectif tant de faciliter leur usage auprs
des administrateurs, cette convention facilitera la mmorisation et permettra galement de
deviner rapidement quelles combinaisons utiliser lorsque les administrateurs rencontreront une
nouvelle fonction/script avanc.
Le dtail de cette convention : Cmdlet Parameter Name and Functionality Guidelines

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 11 / 67
http://msdn.microsoft.com/en-us/library/dd878352(VS.85).aspx
Strongly Encouraged Development Guidelines :
http://msdn.microsoft.com/en-us/library/dd878270(VS.85).aspx

Note : Les noms de paramtre SelectProperty et SelectObject sont rservs, leur usage gnrera
une erreur :
Le nom du paramtre SelectProperty est rserv pour une utilisation ultrieure.
Le nom du paramtre SelectObject est rserv pour une utilisation ultrieure.
3 La gestion du pipeline
Lattribut Parameter facilite la liaison dune valeur dun paramtre donn avec un objet issu du
pipeline. Pour cela on utilise largument ValueFromPipeline :
Function FcntAvance{
Param (
[Parameter(
Mandatory=$True,
Position=0,
ValueFromPipeline = $true)]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}
On prcise ainsi quen cas dutilisation du pipeline lobjet transmis le sera dans la variable
$NomParam. Lexemple suivant nous montre que la prsence de largument ValueFromPipeline
ne met pas pour autant en place les blocs begin, process, end :
1,2,3,4|FcntAvance -count 9
$NomParam=4 $Count=9
Il nous faut les prciser, au minimum le bloc process :
Function FcntAvance{
Param (
[Parameter(
Mandatory=$True,
ValueFromPipeline = $true)]
$NomParam,
$Count)
process {
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}
}
1,2,3,4|FcntAvance count 9

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 12 / 67
$NomParam=1 $Count=9
$NomParam=2 $Count=9
$NomParam=3 $Count=9
$NomParam=4 $Count=9
On constate que la liaison fonctionne et la valeur du paramtre $count est persistante pour tous
les appels du bloc process.
Pour plus de dtails sur le sujet, consultez le chapitre 3.2 du tutoriel L'usage du pipeline sous
PowerShell : http://laurent-dardenne.developpez.com/articles/Windows/PowerShell/Pipelining/
Notez quun script .ps1 peut utiliser le pipeline en dclarant les blocs begin, process et end.
3.1 Diffrences entre la version 1 et la version 2
La gestion des objets issus du pipeline diffre lgrement, prenons lexemple suivant avec la
version 1 de PowerShell :
Function FcntAvanceV1{
Param (
$NomParam,
$Count)
process {
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}
}
Lappel suivant fonctionne :
FcntAvancev1 un 9
$NomParam=un $Count=9
Mais pas celui-ci, car la variable $NomParam nest pas lie :
"un"|FcntAvancev1 -c 9
$NomParam= $Count=9
On doit utiliser $_ reprsentant lobjet courant dans le pipeline :
process {
Write-host "`$NomParam=$_ `t `$Count=$Count"
}
Excutons de nouveau nos deux appels de test, vous remarquerez que cette fois-ci le rsultat est
invers, le premier appel ne fonctionne pas, mais le second oui :
FcntAvance un 9
$NomParam= $Count=9
"un"|FcntAvance -c 9
$NomParam=un $Count=9
Avec PowerShell version 1 on doit tester, dans une fonction utilisant le pipeline et dclarant les
blocs process et end, si la liaison du paramtre se fait partir du pipeline ou pas. Sans prsence
du pipeline cest le bloc end qui est excut :
Function FcntAvanceV1{

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 13 / 67
Param (
$NomParam,
$Count)

process {
if ($_)
{Write-host "`$NomParam=$_ `t `$Count=$Count"}
}

end {
if ($NomParam)
{Write-host "`$NomParam=$NomParam `t `$Count=$Count"}
}
}
Le code prcdent fonctionne correctement avec les deux exemples dappels. Il reste un souci
qui est que lon peut utiliser le pipeline tout en prcisant le paramtre sur la ligne de commande :
"un","Deux"|FcntAvanceV1 -Nom "Trois" -c 9
$NomParam=Un $Count=9
$NomParam=Deux $Count=9
$NomParam=Trois $Count=9
Dans ce cas, les 2 blocs sont excuts, pour viter cela on peut ajouter le test suivant :
process {
if ($NomParam -and $_)
{throw "Impossible de coupler l'usage du pipeline avec le paramtre
`$NomParam"}

Voyons cet aspect avec la version 2 de PowerShell :
Function FcntAvanceV2{
Param (
[Parameter(
ValueFromPipeline = $true)]
$NomParam,
$Count)
process {
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}
}
Testons nos deux appels de test :
FcntAvanceV2 un 9
$NomParam= un $Count=9
"un"|FcntAvanceV2 -c 9

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 14 / 67
$NomParam=un $Count=9
Notez quavec la version 2, la liaison du nom de paramtre $NomParam fonctionne dans les
deux cas.
Pour terminer, testons notre cas derreur :
"Un","Deux"|FcntAvanceV2 -Nom "Trois" -c 9
FcntAvance : L'objet d'entre ne peut tre li aucun paramtre de la commande, soit parce que cette
commande n'accepte pas l'entre de pipeline, soit parce que l'entre et ses proprits ne correspondent aucun
des paramtres qui acceptent l'entre de pipeline.

La version 2 le gre correctement, il dclenche une erreur non bloquante autant de fois quil y a
dobjets reus. Le paramtre $NomParam tant dj li via la ligne de commande, le runtime ne
trouve plus de paramtres lier avec un objet du pipeline et provoque une erreur.
Si on ajoute notre fonction un bloc end, celui-ci sera excut, mais si on ne dclare aucun bloc
le comportement diffre davec la premire la version, sans attribut (FcntAvanceV1 au dbut de
ce chapitre) :
Function FcntAvanceV2{
Param (
[Parameter(ValueFromPipeline = $true)]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}

FcntAvanceV2 un 9
$NomParam= un $Count=9
"un","Deux"|FcntAvanceV2 -c 9
$NomParam=Deux $Count=9
Notez que dans le second appel, la valeur $NomParam est gale au contenu du deuxime objet
mis dans le pipeline, c'est--dire gal la valeur du dernier objet mis.
Testons le cas derreur :
"Un","Deux"|FcntAvanceV2 -Nom "Trois" -c 9
FcntAvance : L'objet d'entre ne peut tre li

FcntAvance : L'objet d'entre ne peut tre li
$NomParam=Trois $Count=9
Pour cet exemple, on saperoit que la prsence de lattribut Parameter, dclarant
ValueFromPipeline, dclenche tout de mme, partir des donnes du pipeline, une itration sur
la liaison, alors que le bloc process nexiste pas. Si on ne dclare que lattribut CmdletBinding
le comportement est identique.
Pour rcuprer lintgralit des donnes, il nous faut, comme sous PowerShell version 1, utiliser
la variable $Input et modifier le type $NomParam en un tableau :
Function FcntAvanceV2{
Param (

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 15 / 67
[Parameter(ValueFromPipeline = $true)]
[string[]] $NomParam,
$Count)
$NomParam=@($input) #Cast d'input en un tableau
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}
"un","Deux"|FcntAvanceV2 -c 9
$NomParam=un Deux $Count=9

Lexemple suivant met en vidence un bug rfrenc, lusage dune fonction au sein dune sous
expression $() provoque des itrations errones :
function Get-Something {
Write-Host 'Got something'
'Something'
}
function test {
[CmdletBinding()] # <- bug
param(
[Parameter(Position=0)]
[string]
$Value = $(Get-Something),
[Parameter(ValueFromPipeline=$true)]
[PSObject]
$PipeObject
)
begin{
Write-Host "Changing the value from '$Value' to 'Something else'." -
ForegroundColor Green
$Value = 'Something else'
}
process{
$Value
}
}
Le problme est quen interne la liaison du paramtre se fait 5 fois, la gestion des attributs de
validation de PowerShell nest pas impacte, eux sont bien excuts une seule fois.
Voir le dtail du bug sur MSConnect :
https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=509985

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 16 / 67
4 Les arguments de lattribut Parameter
Ce chapitre reprend et complte les informations du fichier about_Functions_Advanced_Parameters.txt
Tous ces arguments sont optionnels, ceux tant de type boolen ont par dfaut la valeur $false.
4.1 Mandatory
L'argument Mandatory, de type boolen, indique que le paramtre est obligatoire lorsque la
fonction est excute. Si cet argument n'est pas spcifi, le paramtre est alors un paramtre
optionnel.
Note : Passer en argument la valeur $null un paramtre obligatoire dclenchera une exception.
Attention, si un paramtre portant cet argument dclare une valeur par dfaut, son caractre
obligatoire persiste. C'est--dire que la prsence de ce paramtre sur la ligne de commande sera
toujours obligatoire.
4.2 Position
L'argument Position, de type entier, spcifie la position du paramtre. Si cet argument n'est pas
spcifi, le nom de paramtre ou son alias doit tre spcifi explicitement quand la valeur du
paramtre est dfinie.
De mme, si aucun des paramtres d'une fonction n'a de position, le runtime Windows
PowerShell affecte des positions chaque paramtre selon l'ordre dans lequel ils sont reus.
Note : Il est possible de dclarer plusieurs paramtres dclarants une position identique, en cas
dambigut PowerShell dclenchera une exception :
Impossible de lier les paramtres positionnels, car aucun nom n'a t fourni.
Les nombres indiquant la position peuvent ne pas tre ordonns ni se suivre :
Function TestProperty {
[CmdletBinding()]
Param (
[Parameter(Position=7)]
$Count,
[Parameter(Position=1)]
$Name,
[Parameter(Position=5)]
$test)

"Name = $Name"
"Test = $test"
"Count = $Count"
}
TestProperty un deux trois
Name = un

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 17 / 67
Test = deux
Count = trois
4.3 HelpMessage
L'argument HelpMessage, de type String, spcifie un message contenant une description courte
du paramtre. Pour la dclaration suivante :
[Parameter(Position=0,Mandatory=$true,HelpMessage="Objet analyser.")]
$NomParam="Defaut"
En cas dabsence du paramtre, PowerShell proposera de le saisir et affichera le texte suivant :
applet de commande FcntAvance la position 1 du pipeline de la commande
Fournissez des valeurs pour les paramtres suivants :
(Tapez !? pour obtenir de l'aide.)
NomParam: !?
Objet analyser.
NomParam:
La saisie des caractres !?, suivis dun retour chariot, affichera le texte daide Objet analyser.
Il existe deux autres arguments reconnus pour lattribut Parameter permettant de dfinir le
message daide partir dun fichier de ressources :

#Les valeurs utilises ici existent bien
[Parameter(Mandatory=$true,HelpMessageBaseName="ParameterBinderStrings",
HelpMessageResourceId="PositionalParameterNotFound")] $Test
Malheureusement, la gestion interne de PowerShell nautorise pas dajouter un fichier de
ressources additionnelles afin de grer ces arguments dans une fonction avance. Un petit souci
en cas de localisation de cet argument.
4.4 ValueFromPipeline
L'argument ValueFromPipeline, de type boolen, spcifie que la valeur du paramtre peut
provenir de lobjet mis dans le pipeline. Spcifiez cet argument si la fonction ou le script accde
l'objet complet et pas seulement une proprit de l'objet.
Par convention, le nom standard dun paramtre li au pipeline est InputObject.
Note : Il est possible de dclarer plusieurs paramtres avec cet argument, dans ce cas chacun de
ces paramtres recevra la mme rfrence sur lobjet.

Voir aussi : Understanding ByValue Pipeline Bound Parameters
http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6158.entry
4.5 ValueFromPipelineByPropertyName
L'argument valueFromPipelineByPropertyName, de type boolen, spcifie que la valeur du
paramtre peut provenir dune proprit de lobjet mis dans le pipeline. Spcifiez cet attribut si
les conditions suivantes sont remplies :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 18 / 67
- Le paramtre accde une proprit de l'objet mis dans le pipeline.
- La proprit de l'objet mis porte le mme nom que le paramtre, ou la proprit a le mme
nom quun des alias du paramtre.
L'exemple suivant teste les deux cas :
Function TestProperty {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipelineByPropertyName = $true,
HelpMessage = "Objet analyser.")]
[Alias('Nom')]
[System.String] $Name)
begin {
$StringFormat= "[Nom de paramtre] {0}"
} #Begin
process {
$StringFormat -F $Name
}#process
} #TestProperty
Laccs par nom de proprit, on cre un objet possdant une proprit nomme Name :
$hash=@{};
$hash.Name="Test avec Name"
$object = new-object PSObject -property $hash
$object|TestProperty
[Nom de paramtre] Test avec Name
Laccs par alias de nom de proprit, on cre un objet possdant une proprit nomme Nom :
$hash=@{};
$hash.Nom="Test avec Nom"
$object = new-object PSObject -property $hash ; $object|TestProperty
[Nom de paramtre] Test avec Nom
Si on cre un objet ne possdant pas de proprit nomme Name ou Nom :
$hash=@{};
$hash.Non="Test avec Non.Aucune correspondance."
$object = new-object PSObject -property $hash ; $object|TestProperty
Alors, la tentative de liaison partir du pipeline gnrera lexception suivante :
TestProperty : L'objet d'entre ne peut tre li aucun paramtre de la commande, soit parce que cette
commande n'accepte pas l'entre de pipeline, soit parce que l'entre et ses proprits ne correspondent aucun
des paramtres qui acceptent l'entre de pipeline.
Toutes les classes existantes possdant une proprit Name pourront tre utilises :
Dir c:\temp|TestProperty
[Nom de paramtre] Adobe

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 19 / 67
[Nom de paramtre] Google Toolbar
[Nom de paramtre] VBE

Il est possible de rcuprer plusieurs proprits :
Function TestProperty {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipelineByPropertyName = $true,
HelpMessage = "Objet analyser.")]
[Alias('Nom')]
[System.String] $Name,

[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('Length')]
$Count)

begin {
$StringFormat= "[Nom de paramtre] {0} [Count] {1}"
} #Begin
process {
$StringFormat -F $Name,$Count
}#process
} #TestProperty

$hash=@{};
$hash.Name="Test avec Name"
$hash.Count=5
$object = new-object PSObject -property $hash ; $object|TestProperty
[Nom de paramtre] Test avec Name [Count] 5
Dir|Where {!$_.PSIsContainer}|TestProperty
[Nom de paramtre] A propos de Add-Lib.url [Count] 140
[Nom de paramtre] Revisions.txt [Count] 4935

Notez quil nest pas ncessaire de coupler cet argument avec ValueFromPipeline. Un seul
suffit, mais les deux peuvent tre coupls sur le mme paramtre. Si vous le faites et que lobjet
ne possde pas de proprit de mme nom, le paramtre sera alors li non plus la proprit de
lobjet mis dans le pipeline, mais lobjet, si toutefois le type du paramtre le permet.
Quand un paramtre est li par ByValue et par ByPropertyName, PowerShell essaie de le lier
dans lordre suivant :
liaison par ByValue sans conversion de types,
liaison par ByPropertyName sans conversion de types,

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 20 / 67
liaison par ByValue avec conversion de types,
liaison par ByPropertyName avec conversion de types,
Une transformation implicite, un cast, peut donc avoir lieu lors de la liaison. Vous pouvez tester
ces comportements en modifiant le type du paramtre $Name :
Function TestProperty {
Param (
[Parameter(
ValueFromPipelineByPropertyName = $true,
ValueFromPipeline = $true)]
#[String]$Name # cast implicite de lobjet String
[Int]$Name # cast implicite de lobjet Int
#$Name # tout objet est accept
)

Process { "[Nom de paramtre] $Name" ; $Name.GetType();"`r`n"}
}
$hash=@{}; $hash.Name="Test"
$object = new-object PSObject -property $hash
$hash=@{}; $hash.Name=3
$object2 = new-object PSObject -property $hash
$cp = new-object Microsoft.CSharp.CSharpCodeProvider
$object,$object2,$cp,10,3.5,$null,"" |TestProperty
On passe un objet personnalis possdant une proprit Name, un objet dotnet et un integer :
$object,$object2,$cp,10,3.5,$null,""|TestProperty
Dans le cas o la conversion ne peut se faire, PowerShell dclenche une erreur non bloquante.
Cest le cas pour le type [int] :
TestProperty : Impossible de traiter la transformation d'argument sur le paramtre Name . Impossible de
convertir la valeur Test en type System.Int32 . Erreur : Le format de la chane d'entre est incorrect.

[Nom de paramtre] 3
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType

TestProperty : L'objet d'entre ne peut tre li aucun paramtre de la commande, soit parce que cette
commande n'accepte pas l'entre de pipeline, soit parce que l'entre et ses proprits ne correspondent aucun
des paramtres qui acceptent l'entre de pipeline.

[Nom de paramtre] 10
True True Int32 System.ValueType

[Nom de paramtre] 4
True True Int32 System.ValueType


Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 21 / 67
[Nom de paramtre]
Vous ne pouvez pas appeler de mthode sur une expression ayant la valeur Null.

[Nom de paramtre] 0
True True Int32 System.ValueType
Vous noterez galement que pour le type [int], une chane vide se voit attribuer une valeur par
dfaut, et que la valeur [Double] est arrondie.
tant donn que lon utilise le plus souvent une seule information dun objet, lusage coupl de
ces deux arguments permet daugmenter les possibilits de russite lors de la liaison, sous
rserve que ce couplage ait un sens.

Voir aussi : Understanding ByPropertyName Pipeline Bound Parameters
http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6130.entry
4.6 ValueFromRemainingArguments
L'argument ValueFromRemainingArguments, de type boolen, spcifie que le paramtre
accepte tous les arguments restants qui ne sont pas lis aux paramtres de la fonction :
Function FcntAvance{
#[CmdletBinding()]
Param (
[Parameter(Position=0)]
$NomParam,
$Count,
[parameter(ValueFromRemainingArguments=$true)]
[String[]] $ArgsRestant)
Write-host "`$NomParam=$NomParam `t `$Count=$Count Reste=$ArgsRestant"
}
FcntAvance "Deux" 1 2 3 4
$NomParam=Deux $Count= Reste=1 2 3 4
Note : A partir du moment o on utilise les fonctions avances, on doit prciser nos intentions.
4.7 ParameterSetName
L'argument ParameterSetName, de type String, spcifie le jeu de paramtres auquel un
paramtre appartient. Cet argument implmente une sorte de regroupement fonctionnel de
paramtres. Il permet diffrentes utilisations dune fonction/script avancs selon lappartenance
dun paramtre tel ou tel jeu de paramtres.
Un paramtre ne dclarant aucune appartenance un jeu de paramtres (ParameterSet)
appartient tous les groupes existants dans la fonction ou script.
Un paramtre dclarant une appartenance un jeu de paramtre peut appartenir plusieurs jeux,
mais chaque jeu doit avoir au moins un paramtre unique. Chaque jeu contient au moins un
paramtre.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 22 / 67
Prenons par exemple le cmdlet compil Get-EventLog, en utilisant Reflector.exe on voit quil
utilise deux jeux de paramtres, List et LogName :

Essayons la combinaison de paramtre suivante :
Get-Eventlog -list -logname "System"
Get-EventLog : Le jeu de paramtres ne peut pas tre rsolu l'aide des paramtres nomms spcifis.
Lusage de paramtres utilisant plusieurs jeux de paramtres provoque une exception.
Fonctionnellement on peut utiliser le cmdlet Get-EventLog soit en mode liste, on obtient tous
les journaux de logs, soit en mode nom de journal et dans ce cas on obtient les entres du journal
indiqu, mais on ne peut pas utiliser les deux traitements en mme temps.
Implmentons une fonction offrant le mme comportement que cmdlet Get-EventLog (on
implmente uniquement les paramtres et leurs attributs) :
Function GetEventLog{
[CmdletBinding(DefaultParameterSetName="LogName")]
Param (
[Parameter(ParameterSetName="List")]
[Switch] $AsString,
[Parameter(ParameterSetName="List")]
[Switch] $List,
[Parameter(Position=0, Mandatory=$true, ParameterSetName="LogName")]
[string] $LogName,
[Parameter(ParameterSetName="LogName")]
[ValidateRange(0, 0x7fffffff)]
[int] $Newest)

Write-Host "Traitement..."
}
Geteventlog -list -logname "System"
On obtient le mme message derreur.
Autre exemple avec le cmdlet Get-WMIObject :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 23 / 67

Ce cmdlet dclare trois jeux de paramtres et certains paramtres nappartiennent explicitement
aucun jeu, implicitement ils appartiennent chaque jeu de paramtres dclar.
4.7.1 Validit des jeux de paramtres
Dans l'illustration suivante, la colonne de gauche montre trois ensembles valides de paramtres :

Microsoft MSDN
Le paramtre A est unique et appartient au premier ensemble de paramtres, le paramtre B est
unique et appartient au deuxime ensemble de paramtres, et le paramtre C est unique et
appartient au troisime ensemble de paramtres. Le paramtre D appartient tous les ensembles
de paramtres. Le paramtre E appartient uniquement au deuxime ensemble de paramtres.
Cependant, dans la colonne de droite, aucun des ensembles de paramtres ne dclare de
paramtre unique, ils sont donc invalides. Lunicit dau moins un paramtre dans un jeu permet
au runtime de dterminer quelle fonctionnalit on utilise.
Testons ces deux cas, dabord les ensembles invalides :
Function InvalideParameterSet{
Param (
[Parameter(ParameterSetName="Fonctionnalite1")]
[Parameter(ParameterSetName="Fonctionnalite3")]
[Switch] $A,
[Parameter(ParameterSetName="Fonctionnalite1")]

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 24 / 67
[Parameter(ParameterSetName="Fonctionnalite2")]
[Switch] $B,
[Parameter(ParameterSetName="Fonctionnalite2")]
[Parameter(ParameterSetName="Fonctionnalite3")]
[Switch] $C)

Write-Host "Traitement..."
}
Les appels suivants ne fonctionnent pas, car PowerShell ne sait pas de quel jeu de paramtres il
sagit. Par exemple pour A est-ce quil sagit de la Fonctionnalite1 ou de la Fonctionnalite3 ?
InvalideParameterSet A; InvalideParameterSet B; InvalideParameterSet C
Ceux-ci fonctionnent car on sait de quel jeu il sagit :
InvalideParameterSet A -B; InvalideParameterSet B -C;
InvalideParameterSet -A C
Lappel suivant ne fonctionne pas :
InvalideParameterSet
InvalideParameterSet : Le jeu de paramtres ne peut pas tre rsolu l'aide des paramtres nomms spcifis.
partir du moment o on dclare au moins deux jeux de paramtres, on doit en spcifier au
moins un en prcisant un paramtre sur la ligne de commande. Si on implmente plusieurs
fonctionnalits, le runtime doit savoir laquelle utiliser, il ne peut pas le deviner !
Vous remarquerez que, bien que ces jeux de paramtres soient considrs comme invalides, il
reste possible de les utiliser, il y a "juste" une incohrence dans la mise en uvre.
Testons maintenant les ensembles valides :
Function ValideParameterSet{
Param (
[Parameter(ParameterSetName="PSet1")]
[Switch] $A,
[Parameter(ParameterSetName="PSet2")]
[Switch] $B,
[Parameter(ParameterSetName="PSet3")]
[Switch] $C,
[Switch] $D,
[Parameter(ParameterSetName="PSet2")]
[Switch] $E)

Write-Host "Traitement..."
}
Ici la prsence du paramtre unique dans chaque jeu de paramtre permet au runtime de
dterminer quelle fonctionnalit utiliser :
ValideParameterSet A ; ValideParameterSet B; ValideParameterSet C

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 25 / 67
Les appels suivants sont corrects :
ValideParameterSet -A D; ValideParameterSet -B -E
Mais pas ceux-ci :
ValideParameterSet -A C
InvalideParameterSet : Le jeu de paramtres ne peut pas tre rsolu l'aide des paramtres nomms spcifis.
ValideParameterSet D
InvalideParameterSet : Le jeu de paramtres ne peut pas tre rsolu l'aide des paramtres nomms spcifis.
On utilise des paramtres uniques appartenant de jeux diffrents ou un paramtre appartenant
tous les jeux. Le paramtre D ne permet pas lui seul de dterminer la fonctionnalit que lon
souhaite utiliser.
Enfin pour lappel suivant on obtient la mme erreur :
ValideParameterSet
Pour lviter, on doit prciser, laide de lattribut [CmdletBinding()], quel jeu de paramtre on
utilisera par dfaut :
Function ValideParameterSet{
[CmdletBinding(DefaultParameterSetName="PSet2")]
Param (
[Parameter(ParameterSetName="PSet1")]
[Switch] $A,

Ceci fait, on peut excuter notre fonction/script sans prciser de paramtre et autoriser un
comportement par dfaut. On peut tester le nom du jeu de paramtre en cours laide de la
variable automatique $PSCmdlet :
switch ($PsCmdlet.ParameterSetName)
{
"PSet1" { Write-Host "Fonctionnalit 1 (PSet1)"; break}
"PSet2" { Write-Host "Fonctionnalit 2 (PSet2)"; break}
"PSet3" { Write-Host "Fonctionnalit 3 (PSet3)"; break}
}
Une fois dclar le jeu de paramtre par dfaut, lappel suivant fonctionne :
ValideParameterSet D
Fonctionnalit 2 (PSet2)
La prsence de largument DefaultParameterSetName lve toutes ambiguts.
4.7.2 Lattribut OutputType
Dans la nouvelle version de son ouvrage sur PowerShell, Bruce Payette mentionne lexistence
dun attribut non document nomm OutputType.Son rle consiste prciser le type de la
valeur de retour associe au jeu de paramtre actif :
Function ValideParameterSet{
[CmdletBinding(DefaultParameterSetName="PSet2")]

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 26 / 67
[OutputType("PSet1", [int])]
[OutputType("PSet2", [Byte[]])]
[OutputType("PSet3", [String])]
Param (
[Parameter(ParameterSetName="PSet1")]
[Switch] $A,

Mais dans la version 2, son usage ne modifie pas la valeur de retour, en ltat il permet de
documenter le code.
Voir aussi :
PowerShell V2: ParameterSets
http://blogs.msdn.com/powershell/archive/2008/12/23/powershell-v2-parametersets.aspx
Adding Parameter Sets to a Cmdlet
http://msdn.microsoft.com/en-us/library/ms714647(VS.85).aspx
Dans le projet PSCX, le code source du cmdlet Get-DomainController contient un exemple de
gestion de switchs exclusif bas sur lusage de cet argument.
5 Les attributs de validation
Ce chapitre reprend et complte des informations du fichier about_Functions_Advanced_Parameters.txt
Ces attributs dfinissent la faon dont le runtime Windows PowerShell valide les arguments des
fonctions/scripts avances.
Ils sont identiques ceux prsents dans le tutoriel Les variables contraintes sous PowerShell :
http://laurent-dardenne.developpez.com/articles/Windows/PowerShell/VariablesContraintes/
Ces attributs peuvent exister indpendamment de lattribut Parameter :
Function TestValidation{
Param (
[AllowNull()]
[ValidateRange(5,20)]
[Int] $Number)
"$Number Valide"
}
Dans ce cas, si vous souhaitez utiliser la variable $PSCmdlet, vous devrez prciser lattribut
[CmdletBinding()].
Si vous placez plusieurs attributs de validation sur un paramtre, tous les tests de validation
doivent russir. En cas dchec PowerShell dclenche une exception du type :
System.Management.Automation.ParameterBindingValidationException


Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 27 / 67
Notez galement que la rgle de validation est persistante, le paramtre devient donc une
variable contrainte. Si on interdit daffecter la valeur $null un paramtre, cette rgle reste
valide dans le code de la fonction ou du script pour la variable associe ce paramtre.
Le paramtre doit tre li pour que ses rgles de validation se dclenchent. Si vous liez la valeur
dun paramtre, ou plusieurs, via le pipeline, ses rgles associes se dclencheront chaque
opration de liaison.
La validation nest pas dclenche pour les autres paramtres dont les valeurs ne changent pas.
Dans lexemple suivant labsence darguments, lors de lappel de la fonction, gnre une chane
de caractres vide et un tableau de valeur $null :
Function TestValidation {
Param
(
#[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $userName,
[ValidateNotNullOrEmpty()]
[String[]] $Tab
)
"Paramtres valides"
" `$username -eq [string]::Empty : $($username -eq [string]::Empty)"
" `$username -eq `$null : $($username -eq $null)"
#$username=[string]::Empty #exception
" `$Tab -eq [string]::Empty : $($Tab -eq [string]::Empty)"
" `$Tab -eq `$null : $($Tab -eq $null)"
}
TestValidation
Paramtres valides
$username -eq [string]::Empty : True
$username -eq $null : False
$Tab -eq [string]::Empty : False
$Tab -eq $null : True
Cest un peu droutant, mais on ne peut pas valider une valeur optionnelle qui nest pas spcifie
lors de lappel de la fonction/script.
Pour forcer la validation des paramtres on peut placer les affectations suivantes dans les
premires lignes du code de la fonction/script :
$username=$username
$tab=$tab
La diffrence tant que PowerShell gnre cette fois-ci non pas une exception, mais une erreur
non bloquante de type ValidationMetadataException :
La variable ne peut pas tre valide, car la valeur n'est pas une valeur valide pour la variable userName.

La variable ne peut pas tre valide, car la valeur n'est pas une valeur valide pour la variable Tab.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 28 / 67

On peut donc dire que PowerShell valide dans un premier temps un paramtre, puis la variable
associe.
Les appels suivants sont correctement grs :
TestValidation $null
TestValidation UserName $null
TestValidation : Impossible de valider l'argument sur le paramtre userName . L'argument est null ou vide.
Indiquez un argument qui n'est pas null ou vide et ressayez.
Mais si vous modifiez, pour le paramtre $UserName, lattribut ValidateNotNullOrEmpty en
ValidateNotNull, alors PowerShell effectue un cast avant dexcuter la validation, ce qui fait que
la validation de ce paramtre russi.
Ceci est d aux rgles de transtypage :
($null -as [string]) -eq [String]::Empty
True
$S=$null -as [string]
$S -eq [String]::Empty
True
($null -as [Double]) -eq 0
True
$D=$null -as [Double]
$D -eq 0
True
Loprateur as affecte implicitement la valeur par dfaut du type utilis lors de lopration.
Ces attributs de validation constituent une sorte de contrat sous forme de prconditions.
5.1 AllowNull
L'attribut AllowNull autorise l'argument d'un paramtre obligatoire tre affecte avec la valeur
$Null. Cet attribut ne ncessite pas dargument.
[AllowNul()]
5.2 ValidateNotNull
L'attribut ValidateNotNull spcifie que l'argument du paramtre ne peut pas tre dfini avec
$Null. Le runtime Windows PowerShell gnre une erreur si la valeur du paramtre est $Null.
Cet attribut ne ncessite pas dargument.
Si le paramtre est une collection, celle-ci ne doit pas contenir dlment de valeur $null :
Function TestValidation {
Param
(
[ValidateNotNull()]
[String[]] $Objets
)

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 29 / 67
"Paramtre valide"
$Objets
}
TestValidation @(1,(Get-Date),$null)
Les collections utilisables avec cet attribut doivent implmenter au moins une des interfaces
suivantes : IList, ICollection, IEnumerable, IEnumerator. Notez que la valeur $null est
transforme en chane vide.
Pour retrouver les interfaces implmentes :
$PSVersiontable.GetType().GetInterfaces()
5.3 AllowEmptyString
L'attribut AllowEmptyString autorise une chane vide comme argument d'un paramtre
obligatoire. Cet attribut ne ncessite pas dargument.
5.4 ValidateNotNullOrEmpty
L'attribut ValidateNotNullOrEmpty spcifie que l'argument du paramtre ne peut pas tre
dfini avec $Null, ni tre vide. Le runtime Windows PowerShell gnre une erreur si le
paramtre est spcifi et que sa valeur est soit $Null, soit une chane vide ou un tableau vide.
Cet attribut ne ncessite pas dargument.
Si le paramtre est une collection, celle-ci ne doit pas contenir dlment de valeur $null ou
vide :
Function TestValidation {
Param
(
[ValidateNotNullOrEmpty()]
[Object[]] $Objets
)
"Paramtre valide"
$Objets
}
TestValidation @(1,(Get-Date),$null)
Les collections doivent implmenter au moins une des interfaces suivantes : IList, ICollection,
IEnumerable, IEnumerator.
A la diffrence de lattribut ValidateNotNull, ici le mme code gnre une exception.
5.5 AllowEmptyCollection
L'attribut AllowEmptyCollection autorise une collection vide comme argument d'un paramtre
obligatoire. Cet attribut ne ncessite pas dargument.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 30 / 67
5.6 ValidateCount
L'attribut ValidateCount spcifie le nombre minimal et le nombre maximal d'lments, tous
deux de type integer, que le paramtre, de type collection, peut accepter. Le runtime Windows
PowerShell gnre une erreur si le nombre d'lments se trouve l'extrieur de cette plage :
[ValidateCount(1,26)] # de A Z
[Char[]] $HardDrives
5.7 ValidateLength
L'attribut ValidateLength spcifie la longueur minimale et la longueur maximale, tous deux de
type integer, de la valeur du paramtre (celui-ci est en interne transform en [string]). Le
runtime Windows PowerShell gnre une erreur si la longueur de la valeur du paramtre se
trouve l'extrieur de cette plage. La variable peut tre de type string ou tableau de string :
Function TestValidation {
Param
(
[ValidateLength(3,5)]
#[String[]] $T
[String] $T

)
"Paramtre valide"
$T
}
TestValidation "100"
#TestValidation @("100","1457",$null)
On peut par exemple passer en paramtre un tableau de char condition de modifier la variable
$OFS :
Function TestValidation {
Param(
[ValidateLength(3,5)]
[String] $T
)
"Paramtres valides"
$T
}
TestValidation "Test"
[Char[]] $Chars=@(65,66,67,68,69)
#---Erreur d $OFS
"$Chars".length
#Cast explicite en [String]

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 31 / 67
TestValidation $Chars

$ofs=""
"$Chars".length
TestValidation $Chars
#---Erreur de validation de la longueur
[Char[]] $Chars=@(65,66,67,68,69,70)
TestValidation $Chars
5.8 ValidatePattern
L'attribut ValidatePattern spcifie une expression rgulire validant le contenu du paramtre de
type string. Le runtime Windows PowerShell gnre une erreur si la valeur du paramtre ne
correspond pas au modle de lexpression rgulire :
[ValidatePattern(^([A-Za-z]{3})$)] # Mot de trois lettres
[String] $TriGram="ABC"
5.9 ValidateRange
L'attribut ValidateRange spcifie les valeurs minimales et maximales, tous deux de type object,
de la valeur du paramtre, lui aussi de type [Object]. Le runtime Windows PowerShell gnre
une erreur si la valeur du paramtre se trouve l'extrieur de cette plage :
[ValidateRange("A","Z")]
[Char] $DriveName
Attention cet attribut est inadapt (bugg ?) pour certains types, par exemple il est impossible de
valider une tendue de date. Pour contourner ce problme, on utilisera lattribut ValidateScript.
5.10 ValidateSet
L'attribut ValidateSet spcifie un jeu de valeurs valides pour la valeur du paramtre, qui peut
tre un tableau. Le runtime Windows PowerShell gnre une erreur si la valeur du paramtre ne
correspond pas une des valeurs de ce jeu :
[ValidateSet("HKCR","HKCU","HKLM","HKCC")]
[String] $HiveShortCut
Ici on parcourt et valide chaque lment du tableau de chane de caractres passe en paramtre :
[ValidateSet("HKCR","HKCU","HKLM","HKCC")]
#[String[]] $HiveShortCut
Le type des valeurs de lensemble peut tre de tout type scalaire, mais sous forme de constante :
Function TestValidation {
Param
(
[ValidateSet(5,7,9,12)]
#[Int] $Nb

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 32 / 67
[Int[]] $Nb
)
"Paramtre valide"
$Nb
}

TestValidation @(5,1)
5.11 ValidateScript
L'attribut ValidateScript spcifie un Scriptblock validant le contenu du paramtre. Le runtime
Windows PowerShell gnre une erreur si le rsultat du Scriptblock est faux ou si le Scriptblock
lve une exception.
Dans tous les cas la valeur tester au sein du Scriptblock provient du pipeline. Sachez que la
variable associe au paramtre nest pas encore dclare lorsque Validatescript est appel, on ne
reoit que la valeur du paramtre.
Dans l'exemple suivant, la valeur du paramtre Count doit tre infrieure 4 :
Function Test{
Param (
[ValidateScript({$_ -lt 4})]
[int] $Count
)
$count
}
Test 5
Il est possible de faire appel script ou une fonction existante :
function FnctValidation()
{$_ -lt 4}

Function Test{
Param (
[ValidateScript({FnctValidation})]
#[ValidateScript({&C:\temp\TestValidation.ps1})]
[int] $Count)
$count
}
Test 5
Rappel :
Les attributs drivs suivants partagent le mme comportement sur les variables numrables,
c'est--dire de type collection :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 33 / 67

Enfin sachez que les erreurs dclenches par un attribut de validation ne sont pas bloquantes :
Function Test{
Param (
[Parameter(ValueFromPipeline = $true)]
[ValidateScript({$_ -lt 4})]
[int] $Count)
process { $count }
}
1,5,3,7,9,2|Test
1
Test : Impossible de valider l'argument sur le paramtre Count . Le script de validation $_ -lt 4 pour
l'argument avec la valeur 5 n'a pas retourn une valeur True. Dterminez pourquoi la validation du script a
chou et ressayez.

3
Test : Impossible de valider l'argument sur le paramtre Count . Le script de validation $_ -lt 4 pour
l'argument avec la valeur 7
Test : Impossible de valider l'argument sur le paramtre Count . Le script de validation $_ -lt 4 pour
l'argument avec la valeur 9
2
Nayant pas cod de gestion des erreurs dans le Scriptblock, PowerShell utilise un message
prdfini.
5.11.1 Cration de rgles de validation
Lattribut ValidateScript peut tre utilis pour crer des rgles personnelles de validation
darguments de paramtre ou pour tracer ses modifications.
Prenons le cas o lon veuille imposer la rgle suivante : un chemin ne doit pas contenir de
caractres du globbing, c'est--dire *, ? et [] :
Function Test-AcceptsWildcards{
if ($MyInvocation.CommandOrigin -eq "Internal")
{ Write-Debug "Excution via un attribut" }
else
{ Write-Debug "Excution via un runspace" }
If (
([Management.Automation.WildcardPattern]::ContainsWildcardCharacters($_)))
{

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 34 / 67
$VMEx="System.Management.Automation.ValidationMetadataException"
$EGlobbing="Le globbing (?,*,[]) n'est pas support ({0})."
Throw (new-object $VMEx ($EGlobbing -F $_))
}
#La valeur est valide
$true }
Le premier test sur la variable $MyInvocation.CommandOrigin dtermine si le code est excut
par le runtime via un attribut ou via une affectation dans un runspace.
function Test( [ValidateScript( {Test-AcceptsWildcards} )]
[Parameter(ValueFromPipeline = $true)] $Path)
{ $Path }
"C:\*.exe"|Test
Ainsi, on obtient lerreur suivante :
Test : Impossible de valider l'argument sur le paramtre Path . "Le globbing (?,*,[]) n'est pas support
(C:\*.exe).
5.11.2 Usage de fonction de validation dans un module
des fins de rutilisation, il est possible de regrouper des fonctions ddies la validation de
paramtre au sein dun module. Le problme est quun module dfinit un tat de session diffrent
de la session courante de PowerShell, ce qui fait que dans ce cas la variable $_ ne peut tre
utilise, car elle ne rfrence pas la valeur de largument, mais une autre valeur. Du coup la
validation russit.
On doit donc dclarer un paramtre dans la fonction de validation :
$VMException="System.Management.Automation.ValidationMetadataException"
$ErrorMsg= "Le globbing (?,*,[]) n'est pas support ({0})."

Function Test-ContainsWildcardCharacters($InputObject){
If ([Management.Automation.WildcardPattern]::ContainsWildcardCharacters(
$InputObject))
{ throw (new-object $VMException ($ErrorMsg -F $InputObject)) }
$true }
Puis dans le code de la dclaration de lattribut, on lui passe en ligne de commande la valeur de
son argument :
function Test( [ValidateScript( {Test-ContainsWildcardCharacters $_ } )]
[Parameter(ValueFromPipeline = $true)] $Path)
{ $Path }
"C:\*.exe"|Test
Ainsi, on obtient la mme erreur :
Test : Impossible de valider l'argument sur le paramtre Path . "Le globbing (?,*,[]) n'est pas support
(C:\*.exe).

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 35 / 67
Notez que dans ce contexte la variable $_ est la valeur courante de largument, la prsence dun
segment de pipeline nest donc pas ncessaire.
Ce que nous confirme lexemple suivant :
Test "C:\*.exe"
Mais il existe une autre approche que Bruce Payette mentionne dans la nouvelle version de son
ouvrage, qui est de rcuprer la valeur de la variable $_ dans la porte de lappelant.
Elle ncessite toutefois de prciser lattribut CmdletBinding, ainsi quune clause param vide,
afin daccder la variable $PSCmdlet. Celle-ci permettant daccder aux informations de
contexte de lappelant. En un mot, accder au contenu de la variable $_ de la fonction utilisant le
code de validation :
Function Test-ContainsWildcardCharacters{
#Ncessaire pour accder $PSCmdlet.
[CmdletBinding()]
param ()
$ObjectInScopeOfCaller=$PSCmdlet.SessionState.PSVariable.Get("_").Value
If
([Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Obje
ctInScopeOfCaller))
{ throw (new-object VMException ($MessageTable.EVAGlobbing -F
$ObjectInScopeOfCaller)) }
$true
} #Test-ContainsWildcardCharacters
Le code sen trouve simplifi :
function Test( [ValidateScript( {Test-ContainsWildcardCharacters} )]
[Parameter(ValueFromPipeline = $true)] $Path)
{ $Path }
"C:\*.exe"|Test
Le revers de la mdaille est quun appel de notre fonction en dehors du contexte de lattribut
ValidateScript, qui renseigne automatiquement la variable $_, ne peut pas fonctionner.
Si on souhaite appeler ce type de fonction, on doit renseigner la variable $_ avant dappeler notre
fonction :
Test-ContainsWildcardCharacters "C:\*.exe"
Impossible de trouver un paramtre positionnel acceptant l'argument C:\*.exe .
"C:\*.exe"|Test-ContainsWildcardCharacters
L'objet d'entre ne peut tre li aucun paramtre de la commande, soit parce que cette commande n'accepte
pas l'entre de pipeline, soit parce que l'entre et ses proprits ne correspondent aucun des paramtres qui
acceptent l'entre de pipeline.
$_="C:\*.exe"
Test-ContainsWildcardCharacters
True
$_="C:\*.exe";Test-ContainsWildcardCharacters
"Le globbing (?,*,[]) n'est pas support (C:\*.exe)."

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 36 / 67
La diffrence de comportement, entre les deux derniers appels, est due au fait que dans la
console on excute chaque instruction dans un pipeline diffrent.
Le code suivant fonctionne, car le code dun scriptblock utilise le mme pipeline :
&{
$_="C:\*.exe"
Test-ContainsWildcardCharacters
}
"Le globbing (?,*,[]) n'est pas support (C:\*.exe)."
A vous de choisir quelle est lapproche la plus adapte vos besoins.
5.12 Diffrences de comportement entre une fonction avance et un cmdlet
Extrait du fichier about_Functions_Advanced.txt
Les fonctions avances diffrent des cmdlets compils pour les raisons suivantes :
- La liaison des paramtres des fonctions avances ne lve pas d'exception lorsqu'un tableau de
chanes est li un paramtre boolen.
- L'attribut ValidateSet et l'attribut ValidatePattern ne peuvent pas passer de paramtres
nomms.
- Les fonctions avances ne peuvent pas tre utilises dans les transactions.
6 Cration de paramtres dynamiques
Une fonction/script avanc peut dfinir des paramtres accessibles sous certaines conditions, par
exemple quand :
- l'argument d'un autre paramtre une valeur spcifique,
- on excute le script partir dun contexte de provider particulier,
- on dispose de droits supplmentaires, etc.
La plupart des paramtres dynamiques des cmdlets sont ajouts par des providers lors de
l'excution et sont dsigns sous le nom de paramtre dynamique parce qu'ils sont ajouts
seulement quand ils sont ncessaires, c'est--dire quand la ou les conditions sont remplies.
Ces conditions valident donc la prsence du paramtre dynamique qui renseigne une information
contextuelle supplmentaire. Le plus souvent lusage de paramtre statique, switch et jeu de
paramtres suffit.

Un nouveau mot cl a t ajout au langage, DynamicParam {<liste-instructions>}. Il prcise
le bloc de code dfinissant le ou les paramtres dynamiques. Sa prsence force dclarer un des
blocs Begin, Process, End, sans quoi on obtient une erreur.
De plus, la prsence dun attribut Parameter ou CmdletBinding() est un pr requis
lexcution du bloc DynamicParam. Dans la liste d'instructions, utilisez une instruction If pour

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 37 / 67
spcifier les conditions dans lesquelles le ou les paramtres sont disponibles dans la
fonction/script.
La cration de notre paramtre ncessite dutiliser des classes dotnet du Framework PowerShell.
On doit crer un objet :
- System.Management.Automation.ParameterAttribute pour reprsenter un attribut dun
paramtre, tel que Mandatory, Position ou ValueFromPipeline, ou son jeu de paramtres,
- System.Collections.ObjectModel.Collection[System.Attribute], qui est une liste gnrique
hbergeant les attributs dun paramtre,
- System.Management.Automation.RuntimeDefinedParameter pour reprsenter un paramtre
dynamique et spcifier son nom,
- RuntimeDefinedParameterDictionary pour retourner au runtime les paramtres construit
dynamiquement.

L'exemple suivant, simulant une installation dun logiciel, cre un paramtre dynamique de type
switch nomm Reboot.
Si on prcise ce switch on redmarrera le poste une fois linstallation termine, condition que
lutilisateur de la session possde les droits dadministrateur :
function isAdmin {
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$principal = new-object `
System.Security.Principal.WindowsPrincipal($identity)
$admin = [System.Security.Principal.WindowsBuiltInRole]::Administrator
$principal.IsInRole($admin)
}

function Publish-Application{
[cmdletbinding()]
Param ([String]$Name)

DynamicParam
{
Write-Warning "Traitement de la clause DynamicParam"
if (isAdmin)
{
Write-Warning "Cration du paramtre Reboot "
$attributes = new-object `
System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = 'Admin'
$attributes.Mandatory = $false

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 38 / 67
$attributeCollection = new-object `
System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
$dynParam1 = new-object `
System.Management.Automation.RuntimeDefinedParameter(
"Reboot",
[System.Management.Automation.SwitchParameter],
$attributeCollection)

$paramDictionary = new-object `
System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("Reboot", $dynParam1)
$paramDictionary
}#if
#Else : renvoi implicitement $null
}#DynamicParam

Begin {
Write-Host "Traitement du bloc Begin" fore white
}#begin

End{
$S="Liste des paramtres dynamique : "
# Write-host "$ $($pscmdlet.GetDynamicParameters().Keys)"
$PSBoundParameters
Write-Host "Traitement du bloc End" fore Green
Write-Host "Installation de l'application $Name."
[switch]$Reboot= $null
if ($PSBoundParameters.TryGetValue('Reboot',[REF]$Reboot) )
{
if ($Reboot) #Peut tre false -reboot:false
{Write-Host "Reboot du poste aprs traitement." fore white }
}
}#end
}#Publish-Application

Publish-Application -name "OpenOffice" -Reboot

Notez que :
- les variables attributes, attributeCollection, paramDictionary et dynParam1 persistent
dans la porte courante de la fonction,

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 39 / 67
- la variable du paramtre Reboot nest pas cre, on doit y accder par les variables
PSBoundparameter ou dynParam1.
Le rsultat pour un compte possdant les droits dadministrateur :

Si on ne prcise pas le paramtre -Reboot :

On constate que le paramtre dynamique est tout de mme construit avant lopration de liaison.
Si lutilisateur prcise le paramtre Reboot, mais quil ne possde pas les droits
dadministrateur PowerShell dclenchera lerreur suivante :

Ce qui est normal, car dans ce cas les conditions de cration du paramtre ne sont pas remplies.
Sil ne prcise pas le paramtre Reboot, alors le bloc de cration du paramtre dynamique nest
pas excut :

Si vous d commentez la ligne suivante :
Write-host "Liste des paramtres dynamique : $($pscmdlet.GetDynamicParameters().Keys)"
Un affichage supplmentaire du message "Traitement de la clause DynamicParam" aura lieu, il
est d lappel $PSCmdlet.GetDynamicParameters(). Le bloc DynamicParam est donc excut
chaque appel de la mthode GetDynamicParameters(), par consquent ce bloc ne doit contenir
que du code spcifique la cration de paramtre dynamique, ni plus ni moins.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 40 / 67
tant donn que lappel de Get-Command construit les mtadonnes de lobjet prcis, ce
cmdlet appelle en interne la mthode GetDynamicParameters() afin de retrouver tous les
paramtres de lobjet prcis :
(gcm Publish-Application).Parameters.Values|Where {$_.IsDynamic}|Select
Name

Il reste que lexemple mis en uvre dans la fonction Publish-Application met en vidence le
problme suivant : vous pouvez utiliser un paramtre dynamique sans tenir compte des
conditions de sa cration, mais dans ce cas, comme on la vu, le script est susceptible de
dclencher une exception. Pour la grer soit on utilisera le paramtre ErrorAction, soit on
testera une seconde fois la condition (isAdmin) pour viter cette exception.
Voyons un autre exemple, celui indiqu dans la documentation de PowerShell :
function Sample {
[cmdletbinding()]
Param (
[String]$Name,
[String]$path)

DynamicParam
{
if ($path -match "^HKLM:")
{
$attributes = new-object `
System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = 'pset1'
$attributes.Mandatory = $false
$attributeCollection = new-object `
System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
$dynParam1 = new-object `
System.Management.Automation.RuntimeDefinedParameter(
"dp1",
[Int32],
$attributeCollection)

$paramDictionary = new-object `
System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("dp1", $dynParam1)
$paramDictionary
}
}

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 41 / 67
end{
[Int]$Dp1= $null
if ($PSBoundParameters.TryGetValue('Dp1',[REF]$Dp1) )
{
if ($Dp1)
{Write-Host "Valeur du paramtre dynamique `$dp1=$Dp1" fore white }
}
}
}#Sample
Pour ce cas on reconnat, dans lappel de la fonction, la prsence de la condition laide du
contenu du paramtre Path, il rfrence HKLM :
Sample -name "test" -path "hklm:\" -dp1 5
Lorsquon lira ce code, on est assur quil ne dclenchera pas dexception, sous rserve de
connatre lexistence du paramtre dynamique et de son fonctionnement.
Un autre exemple bas sur une rcriture :
function Sample {
[cmdletbinding()]
Param ([String]$Name)
DynamicParam
{
if ((Get-Location).Provider.Name eq "FileSystem")
{
# Le reste du code est identique celui de lexemple prcdent

}#Sample
Cette fois-ci ce nest plus un paramtre de la fonction qui dtermine la condition, mais la
localisation courante. L aussi la condition est prsente dans le code, cd C:\Windows :
cd C:\Windows
Sample -name "test" -dp1 5
Enfin, le bloc DynamicParam ne doit renvoyer dans le pipeline que des paramtres dynamiques,
sinon on obtient lerreur suivante :
Sample : Impossible de rcuprer les paramtres dynamiques pour l'applet de commande. Le type retourner du
bloc dynamicparam pour l'objet System.Object[] est incorrect. Le bloc dynamicparam doit retourner soit
$null, soit un objet de type [System.Management.Automation.RuntimeDefinedParameterDictionary].

Voir aussi :
Make a parameter mandatory only if another parameter value is provided
http://www.powergui.org/thread.jspa?threadID=10607
Exemple C# bas sur la prsence dun switch

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 42 / 67
http://msdn.microsoft.com/en-us/library/dd878334(VS.85).aspx
7 La variable automatique PSCmdlet
Comme nous lavons dj vu, la prsence dans une fonction ou un script dun attribut Parameter
ou CmdletBinding fait que PowerShell dclare une variable automatique nomme $PSCmdlet.
Cest une instance de la classe interne PSScriptCmdlet qui hrite de la classe PSCmdlet, une
des classes utilises pour crer un cmdlet. Cette variable permet daccder, au travers de ces
mthodes, certaines fonctionnalits du moteur PowerShell.
Function FcntAvance{
[CmdletBinding()]
Param (
[Parameter(
ValueFromPipeline = $true)]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
$pscmdlet|gm |Sort membertype,name
}

FcntAvance un 9
Elle contient les membres publics suivants :
Name MemberType
---- ----------
CommandOrigin Property
CommandRuntime Property
CurrentPSTransaction Property
Events Property
Host Property
InvokeCommand Property
InvokeProvider Property
JobRepository Property
MyInvocation Property
ParameterSetName Property
SessionState Property
Stopping Property

CurrentProviderLocation Method
Dispose Method
Equals Method
GetDynamicParameters Method
GetHashCode Method
GetResolvedProviderPathFromPSPath Method
GetResourceString Method
GetType Method
GetUnresolvedProviderPathFromPSPath Method
GetVariableValue Method
Invoke Method

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 43 / 67
ShouldContinue Method
ShouldProcess Method
ThrowTerminatingError Method
ToString Method
TransactionAvailable Method
WriteCommandDetail Method
WriteDebug Method
WriteError Method
WriteObject Method
WriteProgress Method
WriteVerbose Method
WriteWarning Method
Malheureusement le SDK en ligne ne propose pas de documentation sur cette classe, mais vous
pouvez consulter celle de la classe Cmdlet
Elle permet de :
- dterminer le jeu de paramtres courant (ParameterSetName), sil y en a un,
- dcrire directement dans les diffrents pipelines (WriteError, etc),
- de grer les paramtres -Confirm et -Whatif,
- de retrouver le chemin courant dun provider (CurrentProviderLocation),
- dterminer si la fonction/script peut participer une transaction (TransactionAvailable),
- retrouver les paramtres dynamiques (GetDynamicParameters),
- dextraire une ressource des assembly de cmdlets localiss (GetResourceString), etc.
La mthode WriteCommandDetail permet de tracer le dtail d'excution du pipeline dans
l'eventlog PowerShell, vous devez toutefois configurer les snapins de la manire suivante :
Get-PSSnapin|
Foreach {
Write-Warning "Trace le dtail d'excution du pipeline pour le snapin :`
$_.Name";
$_.LogPipelineExecutionDetails=$true
}
7.1 Gestion des exceptions
La variable $PSCmdlet permet galement de prciser les informations lies une exception :
Function FcntAvance{
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline = $true)]
$NomParam,
$Count)
Begin {
$pscmdlet.WriteDebug("**** Test de log --------")

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 44 / 67
}
Process {
#Throw "Erreur: l'objet n'existe pas."
$ErrorRecord = New-Object System.Management.Automation.ErrorRecord (
(New-Object Exception "Erreur: l'objet n'existe pas."),
"FcntAvance.MonErreur_1",
[System.Management.Automation.ErrorCategory]::ObjectNotFound,
$NomParam
)

#$ErrorRecord.ErrorDetails="Informations supplmentaires: actions
recommandes (Indiquer un objet existant)"
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
end{
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
$pscmdlet|gm |Sort membertype,name
}
}

FcntAvance un 9
Utilisons linstruction Throw($Message) :
Erreur: l'objet n'existe pas.
Au niveau de ligne : 22 Caractre : 12
+ Throw <<<< "Erreur: l'objet n'existe pas."
+ CategoryInfo : OperationStopped: (Erreur: l'objet n'existe pas.:String) [], RuntimeException
+ FullyQualifiedErrorId : Erreur: l'objet n'existe pas.
Avec Resolve-Error on connat la ligne exacte, mais les informations concernant le pipeline ne
sont pas renseignes ni celles des paramtres lis :
Exception : System.Management.Automation.RuntimeException: Erreur: l'objet n'existe pas.
TargetObject : Erreur: l'objet n'existe pas.
CategoryInfo : OperationStopped: (Erreur: l'objet n'existe pas.:String) [], RuntimeException
FullyQualifiedErrorId : Erreur: l'objet n'existe pas.
Si on utilise $PSCmdlet.ThrowTerminatingError($ErrorRecord)
FcntAvance : Erreur: l'objet n'existe pas.
Au niveau de ligne : 1 Caractre : 12
+ FcntAvance <<<< un 9
+ CategoryInfo : ObjectNotFound: (un:String) [FcntAvance], Exception
+ FullyQualifiedErrorId : FcntAvance.MonErreur_1,FcntAvance
On ne connat plus le numro de ligne, mais on peut retrouver lid de lerreur prcis dans le
code : FcntAvance.MonErreur_1.
Avec Resolve-Error les informations concernant le pipeline sont renseignes ainsi que celles des
paramtres lis :
Exception : System.Exception: Erreur: l'objet n'existe pas.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 45 / 67
System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(
ErrorRecord errorRecord)
TargetObject : un
CategoryInfo : ObjectNotFound: (un:String) [FcntAvance], Exception
FullyQualifiedErrorId : FcntAvance.MonErreur_1,FcntAvance
De plus, le champ CommandOrigin contient la valeur Runspace au lieu dInternal lorsquon
utilise linstruction Throw.
Renseigner le champ ErrorDetails informe lutilisateur, de votre fonction/script, des possibles
actions corrigeant lerreur.
Sans :
FcntAvance : Erreur : l'objet n'existe pas.
Avec :
FcntAvance : Informations supplmentaires : actions recommandes (Indiquer un objet existant)
Cette approche est plus explicite pour lutilisateur, le message de lexception restant accessible
via :
$error[0].exception
Erreur: l'objet n'existe pas.
7.2 La variable ErrorView
Avec Throw :
$ErrorView="CategoryView"
FcntAvance un 9
OperationStopped: (Erreur: l'objet n'existe pas.:String) [], RuntimeException
Avec ThrowTerminatingError :
FcntAvance un 9
ObjectNotFound: (un:String) [FcntAvance], Exception
$ErrorView=$null #Affichage normal
Vous pouvez utiliser $PSCmdle.WriteError() pour les erreurs non bloquantes.

Voir aussi, Windows PowerShell Error Records :
http://msdn.microsoft.com/en-us/library/ms714465(VS.85).aspx
Module Write Error: http://poshcode.org/1574
7.3 propos du bloc End
On peut utiliser le bloc End pour librer des objets allous dans dautres blocs, ce bloc est appel
une fois tous les objets du pipeline traits. Mais dans le cas o le mcanisme du pipeline est
interrompu par une exception ou par Control-C, ce bloc ne sera pas appel, car il ny a pas de
propagation de lvnement chaque segment de pipeline.
En revanche vous pouvez implmenter une gestion des exceptions dclenches dans votre
fonction/script autour de lexception PipelineStoppedException :


Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 46 / 67
Process
{
#Gestion de l'erreur PipelineStoppedException
trap [System.Management.Automation.PipelineStoppedException]
{
$Msg="Stop le pipeline via Break."
write-Debug ("[{0}]Process: {1}" F $MyInvocation.InvocationName,$Msg))
#Finalise les ressources
Break
}
...
Ce code grera les exceptions, mais pas larrt via Control-C.
Soyez donc attentif ce point si vous comptez utiliser des ressources qui ne sont pas gres par
le Framework dotnet ou qui ncessiteraient un appel explicite la mthode Dispose().
8 Les arguments de lattribut CmdletBinding
Lattribut [CmdletBinding()] offre la possibilit dimplmenter les paramtres d'attnuation de
risques qui ne sont pas implments par dfaut, savoir -WhatIf et -Confirm
Pour rappel :
-WhatIf affiche un message dcrivant l'effet de la commande, au lieu d'excuter cette dernire, il
permet de simuler lexcution de la commande.
-Confirm invite lutilisateur confirmer ou non l'excution de la commande, et ce, pour chaque
objet quelle traite.
8.1 SupportsShouldProcess
Lorsque l'argument SupportsShouldProcess est dfini sur la valeur $true, il indique que la
fonction avance prend en charge les appels la mthode ShouldProcess qui est utilise pour
demander la confirmation de l'utilisateur avant que la fonction n'excute une action qui
modifierait le systme. La fonction avance peut continuer selon la valeur boolenne retourne
par la mthode ShouldProcess.
Lorsque cet argument est spcifi, les paramtres -Confirm et -WhatIf sont activs pour la
fonction avance.
Note : si l'utilisateur spcifie le paramtre -verbose, il sera avis de l'opration mme sil ny a
pas de demande de confirmation.
Function TestAttenuationRisque1
{ [CmdletBinding(SupportsShouldProcess=$True)]
param(
[Parameter(Position=0, Mandatory = $true,
ValueFromPipeline = $true)]$ID)

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 47 / 67
Begin
{ Function Traitement($Object) {Write-Host "Traite $Object"} }
Process
{
if ($psCmdlet.shouldProcess("Opration Traitement"))
{ Traitement $_}
else {Write-host "Pas de traitement avec ShouldProcess"}
}#Process
}
Dclenchons lappel de la mthode ShouldProcess sans effectuer le traitement :
1..2|TestAttenuationRisque1 whatif
WhatIf : Opration TestAttenuationRisque1 en cours sur la cible Opration Traitement .
Pas de traitement avec ShouldProcess
WhatIf : Opration TestAttenuationRisque1 en cours sur la cible Opration Traitement .
Pas de traitement avec ShouldProcess
Dclenchons lappel de la mthode ShouldProcess en demandant une confirmation :
1..2|TestAttenuationRisque1 confirm
Voici une recopie dcran des diffrents comportements selon les rponses donnes lors des
demandes de confirmation :

On a le choix de confirmer tous les traitements ou aucun ou de les slectionner un par un.
8.1.1 propos des capacits des providers
Les capacits de provider sont des caractristiques implmentes ou supportes par le provider.
Plusieurs peuvent tre spcifies, voire une seule. Pour connatre les capacits dun provider, on
utilise le cmdlet Get-PsProvider :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 48 / 67
Get-PSProvider
Name Capabilities Drives
---- ------------ ------
WSMan Credentials {WSMan}
FileSystem Filter, ShouldProcess {C, D }
PscxSettings None {Pscx}

Ici le provider PSCX ou WSMan nimplmente pas la capacit ShouldProcess, ce qui signifie
que sur ces providers lutilisation des paramtres -WhatIf et -Confirm est inoprant :
cd pscx:
dir w*
#Lappel Remove-Item na aucun effet.
remove-item w* -whatif # ou Confirm
dir w*
De plus, un provider peut ne pas implmenter la gestion de certains cmdlets de provider (
http://msdn.microsoft.com/en-us/library/ee126197(VS.85).aspx ), si cest le cas lexcution dun tel cmdlet
peut navoir aucun effet ou dclencher une exception de type InvalidOperationException :
cd wsman:\localhost
Dir
Remove-Item maxtimeoutms -confirm
Remove-Item : Impossible d'utiliser cette commande dans le chemin d'accs actuel, car Remove-Item n'est pas
pris en charge ce niveau du chemin d'accs de fournisseur.
Il est possible de dterminer quelles capacits le provider courant implmente :
(get-location).provider.capabilities
Voici la liste des cmdlets implmentant le paramtre Whatif :
Get-Help * -Parameter Whatif
Note : le code de la fonction avance doit, dans la section daide, dclarer une entre pour le
paramtre Whatif. Sinon votre fonction ne sera pas liste.
Voir aussi le dtail des capacits des providers :
http://msdn.microsoft.com/en-us/library/system.management.automation.provider.providercapabilities(VS.85).aspx
8.1.2 La mthode ShouldContinue
La variable automatique nomme $PSCmdlet propose galement la mthode ShouldContinue.
Elle est utilise pour demander un second message de confirmation. Elle doit tre appele
lorsque la mthode ShouldProcess retourne $true. Cette mthode nest pas affecte par le
paramtrage des prfrences ou par un paramtre.
Modifions le bloc process de la fonction prcdente :
Process
{
if ($psCmdlet.shouldContinue("Requte ?", "Caption"))
{ Traitement $_}

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 49 / 67
else {Write-host "Pas de traitement avec ShouldContinue"}
}#Process
}
1..3|TestAttenuationRisque1
Ainsi cod, la prsence ou non de -Confirm ou -Whatif n'influence pas l'excution du code, la
demande de confirmation est toujours dclenche.
Pour mettre en place une double confirmation, il faut combiner les deux appels :

Pour plus d'informations sur la faon de demander confirmation, consultez " Requesting
Confirmation " sur MSDN : http://go.microsoft.com/fwlink/?LinkID=136658

Note :
Une fonction avance appelant ShouldContinue devrait galement mettre en application un
paramtre Force, de type [switch], qui permettrait au code de la fonction avance doutrepasser
cette demande de confirmation, et ainsi poursuivre l'opration. Assurez-vous que son
implmentation n'affecte pas les appels ShouldProcess.
Un exemple dimplmentation :
Function TestAttenuationRisque1_2
{
[CmdletBinding(SupportsShouldProcess=$True)]
param(
[Parameter(Position=0, Mandatory = $true,
ValueFromPipeline = $true)] $ID,
[Switch]$Force)
Begin
{ Function Traitement($Object) {Write-Host "Traite $Object"} }

Process
{
if ($psCmdlet.shouldProcess($_, "Opration Traitement"))
{
if ($force or $pscmdlet.ShouldContinue($_, "Opration Traitement"))
{ Traitement $_}
}
else {Write-host "Pas de traitement avec SouldProcess"}
}#Process

}


Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 50 / 67
1..3|TestAttenuationRisque1_2 -whatif
1..3|TestAttenuationRisque1_2 -confirm
8.2 ConfirmImpact
Certaines oprations modifiant le systme sont juges risques, telles que le reformatage d'une
partition active du disque dur. Pour ces cas, le cmdlet ou la fonction avance devrait fixer la
valeur de ConfirmImpact High. Cet argument spcifie quel moment l'action de la fonction
doit tre confirme lors de la mthode ShouldProcess.
L'appel la mthode ShouldProcess affiche une demande de confirmation uniquement lorsque
l'argument ConfirmImpact est gal ou suprieur la valeur de la variable de prfrence
$ConfirmPreference.
Spcifiez cet argument uniquement lorsque l'argument SupportsShouldProcess est galement
spcifi. La valeur par dfaut de cet argument est Medium.
Cet argument force le cmdlet demander une confirmation de l'utilisateur mme lorsque celui-ci
n'a pas prcis le paramtre -Confirm. vitez toutefois une utilisation excessive de la valeur
ConfirmImpact High, noubliez pas qu lorigine PS est un outil dautomatisation de tches.
8.2.1 La variable $ConfirmPreference
Cette variable automatique agit sur le comportement des cmdlets/fonctions avances utilisant
largument ConfirmImpact. Lorsque la valeur de $ConfirmPreference [High (par dfaut),
Medium, Low, None] est infrieure ou gale au niveau de risque de l'action du cmdlet,
PowerShell demande automatiquement la confirmation de l'utilisateur avant d'excuter l'action.
Mais si sa valeur est suprieure au niveau du risque de l'action du cmdlet, PowerShell excutera
laction sans demander de confirmation.
Dans ce cas, lutilisateur devra prciser le paramtre Confirm pour modifier le comportement
induit par la valeur de la variable $ConfirmPreference.

Valeur Description
High Les actions de cmdlet avec un risque lev sont automatiquement confirmes.
Pour activer la confirmation d'une commande spcifique, utilisez -Confirm. Pour
supprimer la confirmation d'une commande spcifique, utilisez
-Confirm:$false
Medium Les actions de cmdlet avec un risque moyen ou lev sont automatiquement
confirmes. Pour activer la confirmation d'une commande spcifique, utilisez -
confirm.
Pour supprimer la confirmation d'une commande spcifique, utilisez
-Confirm:$false.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 51 / 67
Low Les actions de cmdlet avec un risque faible, moyen ou lev sont automatiquement
confirmes.
Pour supprimer la confirmation d'une commande spcifique, utilisez
-Confirm:$false.
None Aucune action de cmdlet n'est confirme automatiquement.
Les utilisateurs doivent utiliser le paramtre -Confirm pour demander la
confirmation de commandes spcifiques.

Pour rsumer, largument ConfirmImpact configure le niveau de confirmation de votre fonction
avance et la variable automatique $ConfirmPreference indique quels sont les niveaux qui
ncessiteront une confirmation :
ConfirmImpact $ConfirmPreference Action
Medium High Pas de demande de confirmation automatique.
Low Medium Pas de demande de confirmation automatique.
None * Aucune demande de confirmation. Mme si on
prcise Confirm.
* None Seule la prsence de Confirm dclenchera une
demande de confirmation.
High High Demande de confirmation automatique.
Medium Low Demande de confirmation automatique.

Dans tous les cas lusage du paramtre Confirm reste possible, sauf si largument
ConfirmImpact est None.
8.2.2 La variable $WhatIfPreference
Elle dtermine si le paramtre -WhatIf est activ automatiquement pour chaque commande qui le
prend en charge. Ses valeurs possibles sont :
0
(par dfaut)
Le paramtre -WhatIf n'est pas activ automatiquement.
Pour l'activer manuellement, utilisez le paramtre -WhatIf
de la commande.
1 Le paramtre -WhatIf est activ automatiquement sur toute
commande qui le prend en charge.
Pour le dsactiver manuellement utilisez : -WhatIf:$false

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 52 / 67
8.3 SupportsTransactions
Bien que la prsence de cet attribut soit correctement interprte, il nest apparemment ni
document ni support par Microsoft, peut-tre dans la prochaine version.
Notez que les proxys de commande gnrent du code utilisant cet attribut
Sa valeur de type boolen indique si la fonction accepte ou non un rollback de transaction
PowerShell. Si elle vaut $true le paramtre UseTransaction est alors ajout la liste des
paramtres de la fonction/script.
Voir aussi $PScmdlet.TransactionAvailable()
8.4 DefaultParameterSetName
Comme nous lavons prcdemment vu, l'argument DefaultParameterSetName spcifie le nom
du jeu de paramtres que Windows PowerShell essaiera d'utiliser lorsqu'il ne pourra pas
dterminer quel jeu de paramtres utiliser. Vous pouvez viter ce problme en faisant du
paramtre unique de chaque jeu de paramtres un paramtre obligatoire :
[CmdletBinding(DefaultParameterSetName="MaValeurParDefaut")]
Le nom attribu DefaultParameterSetName peut tre arbitraire ou reprendre un de ceux utiliss
dans la liste des paramtres.
9 Accder aux dtails dune commande
Le cdmlet Get-Member utilise le systme de rflexion de dotnet afin de renvoyer les membres
dun objet ou dune classe, ce cmdlet renvoie un objet, une donne, dtaillant un objet ou une
classe.
Nous avons vu quil est possible de placer sur un paramtre de fonction des mtadonnes laide
dattributs, ces informations sont destines au compilateur interne de PowerShell. Si on le
souhaite, on peut les manipuler une fois la fonction compile.
9.1 Accder aux informations dune fonction
Cette nouvelle version apporte une nouveaut qui est de retrouver les mtadonnes dune
commande :
Function FcntAvance{
Param (
[Parameter(ValueFromPipeline = $true)]
[ValidateNotNullOrEmpty()]
$NomParam,
$Count)
Write-host "`$NomParam=$NomParam `t `$Count=$Count"
}
Le cmdlet Get-Member renvoi uniquement la liste des membres de la classe FunctionInfo en
tant que tableau dinstances de type MemberDefinition :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 53 / 67
$Fi=Get-Member -input (Get-Item Function:fcntavance)
$Fi.Parameters # Parameters ne contient aucune donne
Pour rcuprer les mtadonnes de notre fonction, on doit utiliser le cmdlet Get-Item :
$Fi=Get-Item Function:fcntavance
Cette fois on rcupre une instance de la classe FunctionInfo.
Huit nouvelles proprits y ont t ajoutes et permettent daccder aux mtadonnes dfinies
par les attributs :

Deux proprits nous intressent, Parameters et ParameterSets :
$Fi.Parameters
Key Value
--- -----
NomParam System.Management.Automation.ParameterMetadata
Count System.Management.Automation.ParameterMetadata
Verbose *System.Management.Automation.ParameterMetadata
Debug *System.Management.Automation.ParameterMetadata
ErrorAction *System.Management.Automation.ParameterMetadata
WarningAction *System.Management.Automation.ParameterMetadata
ErrorVariable *System.Management.Automation.ParameterMetadata
WarningVariable *System.Management.Automation.ParameterMetadata
OutVariable *System.Management.Automation.ParameterMetadata
OutBuffer *System.Management.Automation.ParameterMetadata

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 54 / 67
Parameters renvoie une liste des paramtres de la commande, les paramtres communs sont
prcds dune toile et sont dclars automatiquement comme pour n'importe quel cmdlet. Leur
redclaration dans la liste des paramtres dune fonction/script avanc provoquera une erreur :
Un paramtre nomm ErrorAction a t dfini plusieurs fois pour la commande.
Les paramtres d'attnuation de risques -WhatIf et -Confirm ne sont pas lists, car la fonction
dclare implicitement :
[CmdletBinding(SupportsShouldProcess=$False)]
Si vous dclarez largument SupportsTransactions :
[CmdletBinding(SupportsTransactions=$True)]
Le paramtre UseTransaction, de type switch, est alors ajout par PowerShell :
Parameter Name: UseTransaction
ParameterType = System.Management.Automation.SwitchParameter
Position = -2147483648
IsMandatory = False
IsDynamic = False
HelpMessage =
ValueFromPipeline = False
ValueFromPipelineByPropertyName = False
ValueFromRemainingArguments = False
Aliases = {usetx}
Attributes =
System.Management.Automation.ParameterAttribute
PowerShell version 2 autorise galement le paramtre "-?" qui obtient la rubrique d'aide de la
commande, si celle-ci en contient une.
On pourrait donc utiliser le paramtre -ErrorAction pour masquer un des problmes dun cas
dtude prcdent :
"Un","Deux"|FcntAvance -Nom "Trois" -c 9 ErrorAction SilentlyContinue
$NomParam=Trois $Count=9
Ainsi les erreurs non-bloquantes ne sont plus gnres, mais ce nest pas vraiment une solution.
La valeur du paramtre commun ErrorAction prime sur celle de $ErrorActionPreference, que
ce soit en utilisant le cmdlet Write-Error ou la mthode $PSCmdlet.WriteError().
Il est possible dobtenir le dtail dun paramtre :
$Fi.Parameters.NomParam
Name : NomParam
ParameterType : System.Object
ParameterSets : {[__AllParameterSets, System.Management.Automation.ParameterSetMetadata]}
IsDynamic : False
Aliases : {}
Attributes : {System.Management.Automation.ValidateNotNullOrEmptyAttribute, __AllParameterSets}
SwitchParameter : False
Lobjet renvoy par NomParam est de la classe ParameterMetadata, on peut aussi obtenir le
dtail dun de ces attributs :
$Fi.Parameters.NomParam.Attributes[1]
Position : 0
ParameterSetName : __AllParameterSets

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 55 / 67
Mandatory : False
ValueFromPipeline : True
ValueFromPipelineByPropertyName : False
ValueFromRemainingArguments : False
HelpMessage :
HelpMessageBaseName :
HelpMessageResourceId :
TypeId : System.Management.Automation.ParameterAttribute
Les informations renvoyes diffreront selon le type de lattribut interrog.
La proprit ParameterSets hberge le mme type dinformations sur les paramtres, mais ceux-
ci sont regroups par jeux de paramtres :
$Fi.ParameterSets
Parameter Set Name: __AllParameterSets
Is default parameter set: False

Parameter Name: NomParam
ParameterType = System.Object
Position = 0
IsMandatory = False
IsDynamic = False
HelpMessage =
ValueFromPipeline = True
ValueFromPipelineByPropertyName = False
ValueFromRemainingArguments = False
Aliases = {}
Attributes =
System.Management.Automation.ValidateNotNullOrEmptyAttribute
System.Management.Automation.ParameterAttribute

Parameter Name: Count
ParameterType = System.Object
Position = 1

Si vous utilisez un des prcdents exemples utilisant lattribut ParameterSetName, vous pourrez
accder chaque jeu de paramtre de la manire suivante :
$Fi.ParameterSets.Count
$Fi.ParameterSets.Item(0)
$Fi.ParameterSets.Item(0)|Where {$_.name eq "LogName "}
Ces informations pourront, par exemple, nous aider construire une partie de la documentation
dune fonction avance ou gnrer automatiquement une partie dun jeu de tests.
Nous avons pu obtenir des mtadonnes dune fonction laide du provider de fonction, mais
comment obtenir des informations sur un cmdlet compil ?
9.2 Accder aux Informations dun cmdlet
PowerShell nutilisant pas de provider pour les cmdlets, Get-Item ne peut fonctionner. Cest
pour cette raison quil vaut mieux dans tous les cas utiliser Get-Command qui renvoie lui aussi
les informations dun cmdlet. La version 2 permet de rcuprer des informations sur les

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 56 / 67
fonctions, la diffrence est quun cmdlet contient des informations supplmentaires, la classe de
lobjet renvoy sera donc approprie la commande rcupre :

Par exemple, un cmdlet contient un champ PSSnapIn de type PSSnapInInfo, un script externe
.ps1 contient un champ Path, ou une application un champ FileVersionInfo.
Sachez que lobjet rcupr par Get-Command peut tre excut laide de loprateur & :
$Fi=Get-Command -Type Function fcntavance
&Fi
$App=Get-Command -Type Application notepad.exe|select unique
&$App
$Ci=Get-Command -Type Cmdlet Get-Item
&$Ci
9.3 Accder aux informations dun fichier script
Les scripts peuvent galement utiliser les mmes fonctionnalits avances quune fonction,
comme le montre lexemple suivant :
http://blogs.msdn.com/powershell/archive/2008/12/23/advanced-functions-and-test-leapyear-ps1.aspx
On utilisera galement Get-Command :
$Si= Get-Command .\Test-LeapYear.ps1
#$Si= Gcm "$pwd\Test-LeapYear.ps1"
Cette fois on rcupre une instance de la classe ExternalScriptInfo.
9.4 Accder aux informations dun module
Il est possible dobtenir les informations dun module PowerShell, mais tant donn quun
module peut hberger plusieurs commandes utilisant soit du code natif soit du code compil, les
classes des instances renvoyes par Get-Command ne seront pas toujours les mmes, mais elles
driveront toutes de CommandInfo.
Import-Module BitsTransfer
$Tcmd=Get-Command -Module BitsTransfer ; $Tcmd[0]|Get-Member

Module Property System.Management.Automation.PSModuleInfo Module {get;}

$M=Get-Module BitsTransfer

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 57 / 67
$M|Get-Member
Get-Module renvoie une instance de la classe PSModuleInfo, cest elle qui contient les
mtadonnes du module :
TypeName: System.Management.Automation.PSModuleInfo

Name MemberType Definition
---- ---------- ----------
AsCustomObject Method psobject AsCustomObject()

ExportedAliases Property System.Collections.Generic.Dictionary`2[[System.String,
ExportedCmdlets Property System.Collections.Generic.Dictionary`2[[System.String,
ExportedFormatFiles Property System.Collections.ObjectModel.ReadOnlyCollection`1[[System.String,
ExportedFunctions Property System.Collections.Generic.Dictionary`2[[System.String,
ExportedTypeFiles Property System.Collections.ObjectModel.ReadOnlyCollection`1[[System.String,
ExportedVariables Property System.Collections.Generic.Dictionary`2[[System.String,
Guid Property System.Guid Guid {get;}


Voir aussi ce bug, li Get-Command, lorsquil existe deux cmdlets de mme nom :
https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=482523
9.5 Une approche du scripting base sur des plug-ins
Sur le blog de MS-PowerShell, James Brundage propose une approche de dveloppement de
script base sur un mcanisme de plug-in :
http://blogs.msdn.com/powershell/archive/2008/12/25/get-commandplugin.aspx
La fonction avance Get-CommandPlugin utilise les mtadonnes pour excuter un ensemble de
commandes bases sur une signature commune :
#Affiche les plug-ins Get-CodeFromxxx
Get-CommandPlugin (gcm Get-Code) -preposition "From"
#La fonction Get-Code excute les plug-ins prcdents
Get-code http://blogs.msdn.com
10 Proxy de cmdlet
Nous avons rapidement abord le principe des mtadonnes sous PowerShell version 2, elles
dcrivent des cmdlets, des scripts ou des fonctions, on peut donc connatre les dtails internes
dune commande. Sous PowerShell une mtadonne nest pas inerte, elle nest pas quune
description, on peut interagir avec elles pour crire des programmes qui manipulent des
programmes, appel aussi la mta programmation.
Une autre des avances de cette version concerne lcriture de proxy de cmdlet, le principe est
dencapsuler une commande, compile ou pas, afin de modifier son comportement. Par exemple,
restreindre les fonctionnalits d'un cmdlet en supprimant un ou plusieurs de ces paramtres, ou
ajouter une fonctionnalit.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 58 / 67
Les mtadonnes dune commande sont hberges, au travers des classes drives de
CommandInfo, dans un champ daccs priv de type CommandMetadata. Il est possible de
crer une instance de ce type :
$MetaData= New-Object System.Management.Automation.CommandMetaData(
Get-Command Get-Item )
On utilise son constructeur suivant :
public CommandMetadata ( CommandInfo commandInfo )
Laffichage de notre variable $MetaData nous renvoie quelques informations supplmentaires,
notamment la valeur de lattribut ConfirmImpact, la plupart tant dj prsentes dans les classes
drives de CommandInfo.
Lattrait de cette instance est quelle peut tre utilise pour crer une commande base sur une
autre commande. On la passe en argument au constructeur statique de la classe ProxyCommand:
$MetaProg=[System.Management.Automation.ProxyCommand]::create($MetaData)
Vous pouvez aussi utiliser une redirection dans un fichier pour rcuprer le code gnr :
$MetaProg > ProxyGetItem.ps1
Laffichage de la variable $MetaProg nous indique que cet objet contient du code :
$MetaProg
[CmdletBinding(DefaultParameterSetName='Path', SupportsTransactions=$true)]
param(
[Parameter(ParameterSetName='Path', Mandatory=$true, Position=0, ValueFromPipeline=$true,
ValueFromPipelineByProper
tyName=$true)]
[System.String[]]
${Path},
Ce code correspond, au moins pour les paramtres, la transcription du code C# du cmdlet Get-
Item :

Cette transcription, gnre en interne laide des mthodes GetBegin, GetParamBlock,
GetCmdletBindingAttribute, GetHelpComments,, utilise pour les noms de variable la notation
${Path}, elle est identique $Path, la diffrence tant, pour la premire, le possible usage
despaces dans le nom de la variable.
La variable $MetaProg est bien un proxy (ou stub). Son principe est de mettre disposition du
dveloppeur "lenveloppe" dune commande, ce qui lui permettra de la modifier selon ses
besoins. Le proxy de commande ne permet pas de modifier le code de la commande quil
enveloppe, mais juste son paramtrage, il ne sagit donc pas dhritage de cmdlet. Le proxy de
commande est un intermdiaire qui lon confie une charge, mais cest vous de dfinir cette
charge.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 59 / 67
Le code de ce proxy est constitu dune signature, la liste des paramtres, et des blocs Begin,
Process et End.
PowerShell version 2 propose un mcanisme daccs au pipeline de la commande concerne, le
terme US utilis est steppable pipeline que je traduirais par pipeline pas pas ou pipeline
squenc.
10.1 Steppable Pipelines
Un pipeline pas pas relie le pipeline de la commande encapsule au pipeline du code de votre
proxy et vous autorise contrler les blocs Begin, Process et End de la commande concerne.
On doit imprativement utiliser un Scriptblock pour crer ce type de pipeline.
Reprenons le code gnr prcdemment :
$MetaProg > ProxyGetItem.ps1
10.1.1 Bloc Begin
Ce bloc prpare les paramtres additionnels et la gestion du pipeline. Occupons-nous dans un
premier temps de celle-ci.
Les premires lignes grent le paramtre OutBuffer, puis on rcupre les mtadonnes de la
commande concerne en prcisant son nom et son type
(System.Management.Automation.CommandTypes). :
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Get-Item','Cmdlet')
La suivante cre un Scriptblock, son contenu excutera la commande en lui passant les
paramtres lis :
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
Cest donc notre fonction proxy qui dclenche lexcution de la commande, ici Get-Item.
Le Scriptblock ne doit contenir quune commande ou un pipeline :
$scriptCmd = {"Test sans pipeline, ni commande"}
Sinon PowerShell dclenchera lexception suivante lors de lexcution du proxy :
Exception lors de l'appel de GetSteppablePipeline avec 1 argument(s) : Ne peut convertir qu'un bloc
de script contenant exactement un pipeline ou une commande. Les expressions ou les structures de contrle ne
sont pas autorises. Vrifiez que le bloc de script contient exactement un pipeline ou une commande.
Lavant-dernire ligne obtient, du Scriptblock $ScriptCmd, laccs au mcanisme du pipeline de
la commande :
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
Notez que ce Scriptblock na pas t excut. On lui passe en argument lorigine de notre
commande (Runspace).
Et enfin la dernire ligne appel le bloc Begin de notre commande en lui passant en argument la
variable automatique $PSCmdlet :
$steppablePipeline.Begin($PSCmdlet)
Celle-ci sert configurer notre commande avec les informations de contexte dexcution de
notre fonction. Cest donc cette ligne qui excute notre commande en pas pas.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 60 / 67
Comme tout bloc Begin, ici aussi il est excut une seule fois, dans ce cas on excute le dbut du
bloc Begin du proxy, puis lintgralit de celui de la commande et enfin on revient terminer celui
du proxy. Ainsi, on lie bien le bloc Begin du proxy celui de la commande encapsule.
Lenchanement de ce bloc au sein dun pipeline ne diffre pas de la version 1 de PowerShell.
10.1.2 Bloc Process
Le bloc process est quant lui rduit sa plus simple expression. On excute le bloc Process de
notre commande au travers du pipeline pas pas, $steppablePipeline. Cette mthode propose
plusieurs surcharges, ici on lui passe en argument lobjet que notre fonction proxy est susceptible
de recevoir du pipeline, si toutefois notre commande en attend un :
process
{
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
Le bloc try-catch gre toutes les exceptions pouvant tre dclenches.
Il faut noter au moins trois choses sur le comportement de ce type de pipeline :
1. les instructions situes aprs lappel de $steppablePipeline.Process sont excutes une
fois que le bloc Process de la commande a mis dans le pipeline, non pas un, mais tous
les objets quil doit traiter. Et ceci, pour chaque objet reu par le pipeline du proxy. Cest
le comportement normal du pipeline.
2. Le rsultat de $steppablePipeline.Process est automatiquement mis dans le pipeline
construit lors de lappel du proxy et pas dans un pipeline indpendant, ce qui fait quon
ne peut pas le rcuprer. On ne peut manipuler que les objets mis en amont du pipeline,
ceux mis par le pipeline pas pas ne nous sont pas accessibles, mais le sont pour les
segments suivants. Le pas--pas ne se fait pas sur les objets renvoys par la commande,
mais uniquement sur ceux reus par le proxy.
3. Si vous appelez plusieurs fois la mthode Process du pipeline pas pas, lobjet ou les
objets seront mis plusieurs fois.

Lenchanement de ce bloc au sein dun pipeline ne diffre pas de la version 1, en revanche
lusage de la mthode Process, de la classe SteppablePipeline, nitre pas sur les lments que la
commande encapsule renvoi.
10.1.3 Bloc End
Ce bloc excute le bloc End de la commande, comme tout bloc End il est excut une seule
fois lors de la finalisation du pipeline :

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 61 / 67
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
Lenchanement de ce bloc au sein dun pipeline ne diffre pas de la version 1. Par contre, toutes
les instructions situes aprs lappel de $steppablePipeline.Process de chaque proxy seront
excutes les une la suite des autres avant ce bloc.
Et enfin, il reste le bloc daide, contenant simplement des instructions de redirection vers l'aide
dorigine de la commande utilis dans le proxy :
<#

.ForwardHelpTargetName Get-ChildItem
.ForwardHelpCategory Cmdlet

#>

Note :
Si vous encapsulez une commande utilisant uniquement le bloc End, tel que Sort-Object, alors
les 3 trois blocs sont excuts, le bloc Process reoit bien tous les objets du pipeline, mais
lappel $steppablePipeline.Process($_) na aucun effet. Dans ce cas lenchanement de ces
blocs au sein dun pipeline ne diffre pas de la version 1.
10.2 Gestion des erreurs
Les erreurs non-bloquantes ninfluent pas sur le fonctionnement dun proxy de commande.
Une exception est dclenche si la commande encapsule nexiste pas ou plus.
TestProxyFunctionPause
Le terme TestProxyFunctionPause n'est pas reconnu comme nom d'applet de commande, fonction, fichier de
script ou programme excutable. Vrifiez l'orthographe du nom, ou si un chemin d'accs existe, vrifiez que le
chemin d'accs est correct et ressayez.
Une exception quel quelle soit provoquera larrt du pipeline.
Si, par exemple, vous placez une instruction Break dans le bloc Process, alors lenchanement du
pipeline est rompu. Dans ce cas les blocs End ne seront pas excuts, mais aucune erreur nest
gnre.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 62 / 67
10.3 Suppression de paramtres
Il suffit de ne pas proposer dans la clause Param du proxy, le ou les paramtres concerns. Ainsi,
on est assur que lors de la liaison le ou les paramtres ne pourront tre transmis.
10.4 Ajout de paramtres
Lajout de paramtre vous oblige coder la logique associe et vous assurer que le ou les
nouveaux paramtres ne seront pas transmis la commande encapsule, car cela provoquerait
une erreur lors de la liaison. Prenons comme exemple celui propos par Jeffrey Snover dans ce
post :
Extending and/or Modifing Commands with Proxies
http://blogs.msdn.com/powershell/archive/2009/01/04/extending-and-or-modifing-commands-
with-proxies.aspx

Pour grer le paramtre additionnel $SortBy, il procde de la manire suivante :
Il ajoute le paramtre additionnel dans la liste des paramtres :
param(
...
${SortBy}) #Peut contenir un objet ou un tableau dobjets
...
Puis, dans les premires lignes du bloc Begin du proxy, il teste la prsence du paramtre
additionnel, sil existe il le supprime de la liste des paramtres et construit le Scriptblock du
nouveau traitement :
if ($SortBy)
{
[Void]$PSBoundParameters.Remove("SortBy")
$scriptCmd = {& $wrappedCmd @PSBoundParameters |
Sort-Object -Property $SortBy
}
}
Notez que la variable ScriptCmd contient un pipeline utilisant la commande Sort-Object qui
propage le nouvel argument du proxy via son argument -Property. Aucun code nest ajout la
commande dorigine, mais on spcialise tout de mme le comportement de la commande
encapsule.
Si le paramtre additionnel nest pas prcis, alors la commande est excute normalement :
else
{ $scriptCmd = {& $wrappedCmd @PSBoundParameters } }
Vous trouverez galement, dans le post cit, un module facilitant la cration dinstance de type
ParameterAttribute et de proxy de commande.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 63 / 67
Vous pouvez utiliser un script ou une fonction pour hberger votre proxy, de mon cot je prfre
utiliser une fonction dans un module, qui est aussi un fichier, ce qui simplifie, entre autres, le
chargement et le dchargement du proxy.
Si vous nommez votre fonction avec le mme nom que la commande dorigine, cest la fonction
qui sera prioritaire sur la commande dorigine.

Dautres exemples :
Invoke-Command Proxy :
http://nullreference.spaces.live.com/blog/cns!C6138C01B9E969DF!1187.entry
Add filepath to convertto-html :
http://dmitrysotnikov.wordpress.com/2009/10/08/add-filepath-to-convertto-html/
Proxy for import-module :
http://richardsiddaway.spaces.live.com/Blog/cns!43CFA46A74CF3E96!2703.entry
Un wrapper pour Out-Default, par Bruce Payette :
http://poshcode.org/803
Comment implmenter Dir /a:d ?
http://blogs.msdn.com/powershell/archive/2009/03/13/dir-a-d.aspx
Ce code dexemple propose galement une gestion des paramtres dynamiques de la
commande encapsule.
11 Scriptblock et attributs
Un Scriptblock peut utiliser des attributs et accde la variable automatique $PScmdlet :
$sb={
param (
[Parameter(Position=0, Mandatory=$false,ValueFromPipeLine=$true)]
[string] $Nom = "ScriptBlcok"
)
$pscmdlet|gm|Sort membertype,name
}

&$sb
Il est donc possible dutiliser des "Scriptblock avances" implmentant ShouldProcess ou des
paramtres dynamiques, etc.
Notez que ses mtadonnes, de type ScriptInfo, ne semblent pas accessibles nativement, mais Il
reste possible de convertir ce Scriptblock en une fonction.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 64 / 67
12 Construire laide en ligne
Une autre avance concerne lintgration de la documentation au sein du code dune fonction ou
dun script, aussi appel AutoHelp.
Deux nouveaux tokens dlimitent une zone de documentation multi lignes : <# et #>
La structure de ce type daide intgre est la suivante :
<#
.< mot cl d'aide>
< contenu d'aide associ>
#>
Il est possible de dfinir la documentation en utilisant des commentaires mono ligne :
# .< mot cl d'aide>
# <contenu d'aide associ >
La prsence des caractres < >, en dehors dun commentaire multi lignes, sert ici de dlimiteur et
ne fait pas partie la syntaxe :
<#
.Example
PS C:\> MaCommande $Variable|Select First 4
Etc.
#>
Certains mots cls daide, tel que Example, peuvent tre prciss plusieurs fois, dautres sont
usage unique.
Consultez le fichier about_Comment_Based_Help.txt pour le dtail de cette convention et les
rgles de formatage qui sy appliquent.
Lusage de certains paramtres tels que Role, Component et Fonctionality, du cmdlet Get-Help
ne fonctionne pas, en tout cas on ne sait pas trop comment les utiliser, part de cette manire :
Get-Command |Foreach {(get-help $_.name).Component}
Donc, nhsitez pas consultez, le site MsConnect car cette fonctionnalit contient quelques
bugs. De plus la prise en compte des retours la ligne ne semble possible quavec un format de
fichier ASCII.
12.1 Construire un fichier daide localis au format MAML
Une autre possibilit facilitant la localisation est dutiliser un fichier XML respectant le schma
MAML (Multi-Agent Modeling Language) et contenant les mmes rubriques.
Chaque fichier daide localis doit tre plac dans un rpertoire portant le mme nom que celui
de la culture cible (fr-Fr) ou une culture neutre (fr). Le fichier daide par dfaut sera plac dans
le rpertoire du script, il sera utilis sil nexiste pas de fichier localis pour la culture courante.
Nous aurons donc, pour le script Test.ps1, larborescence suivante :


Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 65 / 67

C:\Scripts\Test.ps1
#une seule culture cible
C:\Scripts\de-DE\Test-Help.xml #Culture allemande
C:\Scripts\en-US\Test-Help.xml #Culture amricaine
#plusieurs cultures cibles
C:\Scripts\en\Test-Help.xml #Cultures anglaises
C:\Scripts\fr\ Test-Help.xml #Cultures franaises
C:\Scripts\Test-Help.xml #Culture invariante
La liste des noms de culture : http://msdn.microsoft.com/fr-fr/library/system.globalization.cultureinfo.aspx

Pour prciser le nom du fichier daide externe on utilise la balise de commentaire .ExternalHelp
# .ExternalHelp C:\Scripts\Test-Help.xml
# .ExternalHelp C:\Scripts\Script.ps1.xml
Les contraintes sont les suivantes :
le dbut du nom de fichier daide doit correspondre au nom complet du module, de la
fonction ou du script avec son extension,
le chemin doit tre un nom de chemin complet,
il ne peut pas rfrencer de variable,
ni contenir despace (bug ?). Si cest le cas, utilisez un nom de fichier DOS 8.3. Sous
Cmd.exe utilisez la commande Dir /x.
Vous pouvez aussi utiliser le script ..\Help\GetShortPath.ps1 propos dans les sources. Il
nest pas ncessaire de prciser le nom complet au format 8.3, seuls les rpertoires ou le
nom de fichier comportant un espace peuvent ltre.
Par convention, le nom du fichier XML peut tre postfix avec Help.
La valeur de l'argument de la balise ExternalHelp (C:\MyScripts\MyHelpfile.xml) semble
rsolue de la manire suivante :
Le nom de fichier est spar du reste du chemin. Ce chemin (C:\MyScripts) devient le
dossier de dpart pour la recherche.
Le systme d'aide recherche un dossier portant le nom de la culture dinterface du
systme d'exploitation (UI culture), telle que "en-US " ou "fr-FR ", dans les sous-dossiers
du rpertoire de dmarrage. (C:\MyScripts\fr-FR).
Si le fichier MAML spcifique n'est pas trouv, alors la logique de recherche de langue
de secours est applique et les recherches du systme d'aide se font sur les dossiers
portant un nom de langue alternative, tel que "en " ou "fr ". (C:\MyScripts\fr)
Si le fichier MAML n'est toujours pas trouv, le systme d'aide le recherche alors dans le
dossier de dpart (C:\MyScripts\MyHelpFile.xml)
noter que le chemin daccs du fichier daide semble tre mis en cache par PowerShell, il faut
donc, lors de la mise au point de laide, recharger le script ou recrer lobjet pour la prise en
compte des modifications du fichier XML.

Laurent Dardenne, libre de droits pour tous les usages non commerciaux. Page 66 / 67
Pour vous aider construire le squelette dun fichier XML MAML, vous pouvez utiliser les
scripts suivants :
New-MAML : http://www.poshcode.com/1338
New-XML : http://www.poshcode.com/1244
Lors de mes tests de localisation, jai constat que la modification de la culture du thread courant
ninfluenait pas la recherche du fichier daide localis. Lusage de la balise ExternalHelp dans
un script ne fonctionne pas correctement :
Get-Help "$pwd\Script.ps1"
Seul le fichier XML prsent dans le mme rpertoire est pris en compte, de plus la prsence dun
rpertoire ayant pour nom celui de la culture courante empchera le chargement de ce fichier
daide.

Voir aussi :
How to Write Cmdlet Help : http://msdn.microsoft.com/en-us/library/aa965353(VS.85).aspx
Creating the Cmdlet Help File : http://msdn.microsoft.com/en-us/library/bb525433(VS.85).aspx
User Interface Language Management (Language Fallback in the Resource Loader) :
http://msdn.microsoft.com/en-us/library/dd374098(VS.85).aspx
La page suivante contient de nombreux lien sur le sujet :
http://www.codeplex.com/wikipage?ProjectName=DocProject&title=Sandcastle%20Help
Utilisation de la proprit InvariantCulture : http://msdn.microsoft.com/fr-fr/library/4c5zdc6a(VS.80).aspx
Exemple de fichier daide dun module Powershell V2 :
http://stackoverflow.com/questions/1432717/powershell-v2-external-maml-help

Il est galement possible dutiliser une page web comme une aide online, consultez les posts
suivants :
http://www.leeholmes.com/blog/GetHelpNdashOnline.aspx
http://chadwickmiller.spaces.live.com/Blog/cns!EA42395138308430!846.entry
13 Liens
Recommandations de dveloppement de lquipe Microsoft PowerShell :
http://blogs.msdn.com/powershell/archive/2009/04/16/increasing-visibility-of-cmdlet-design-guidelines.aspx
Cmdlet Development Guidelines : http://msdn.microsoft.com/en-us/library/ms714657(VS.85).aspx

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

14 Conclusion
Il reste srement des cas tudier, ce tutoriel vous donne de nombreux lments pour les raliser
de votre ct.
Ces nouvelles possibilits tirent le scripting vers le "haut" en simplifiant le dveloppement de
traitements spcialiss. Lquipe de dveloppement de PowerShell nous dmontre quil est
possible de faire simple, on se concentre sur le quoi et pas sur le comment. Toutefois, ces
nouvelles possibilits ncessitent un temps dapprentissage consquent, mais le bnfice en vaut
la chandelle et vous ne coderez plus de la mme manire.
Jai pu constater maintes reprises que la documentation offline du produit est incomplte, voire
errone. Pour aborder ces nouveauts laide fournie ne contient pas les dtails importants quant
au fonctionnement, ni dexemples consquents. Je me suis souvent appuy sur Reflector pour
trouver les informations manquantes, sans lui il maurait t difficile dapprofondir certains
points.
La comprhension du fonctionnement ne pose pas de problme particulier, mon avis la
difficult dun tel codage rside dans la connaissance, ou plutt dans la mmorisation des
diffrentes rgles qui peuvent sadditionner.
Ce type de dveloppement peut vous amener aborder le SDK et les comportements sous-
jacents qui sont d'habitude transparents ou peu exploits.
En mme temps rien ne vous oblige implmenter toutes ces nouveauts dans vos prochains
scripts. De savoir quelles existent et quels sont leurs usages, vous permettra de les aborder
progressivement.
Certains bugs cits la fin du chapitre Diffrences entre la version 1 et la version 2 , limite
mon avis lusage des fonctions avances. Par contre, je ne sais pas si Microsoft envisage de livrer
prochainement un patch pour corriger ces quelques bugs mineurs.
Enfin en cas de problme, nhsitez pas consulter MSConnect ou la documentation online US
qui est mise jour suite aux remarques remontes sur MSConnect :
http://technet.microsoft.com/en-us/library/bb978525.aspx
Il reste, li au code, dautres nouveauts importantes telles que les modules, les vnements,
En attendant, bon dev !

Vous aimerez peut-être aussi