Vous êtes sur la page 1sur 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-etscripts-avancees-sous-PowerShell-version-2/fichiers/Les-fonctions-et-scripts-avancees-sousPowerShell-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 1 / 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 3 CONVENTION DE NOMMAGE DE PARAMETRES ...........................................................................................10

LA GESTION DU PIPELINE ........................................................................................................................11 3.1 DIFFERENCES ENTRE LA VERSION 1 ET LA VERSION 2 ................................................................................12

LES ARGUMENTS DE LATTRIBUT PARAMETER ..............................................................................16 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.7.1 4.7.2 MANDATORY.............................................................................................................................................16 POSITION ...................................................................................................................................................16 HELPMESSAGE ..........................................................................................................................................17 VALUEFROMPIPELINE ...............................................................................................................................17 VALUEFROMPIPELINEBYPROPERTYNAME ...............................................................................................17 VALUEFROMREMAININGARGUMENTS ......................................................................................................21 PARAMETERSETNAME ..............................................................................................................................21 Validit des jeux de paramtres...........................................................................................................23 Lattribut OutputType ..........................................................................................................................25

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 7

CREATION DE PARAMETRES DYNAMIQUES ......................................................................................36 LA VARIABLE AUTOMATIQUE PSCMDLET .........................................................................................42 7.1 7.2 7.3 GESTION DES EXCEPTIONS .........................................................................................................................43 LA VARIABLE ERRORVIEW ........................................................................................................................45 PROPOS DU BLOC END ............................................................................................................................45

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 2 / 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 9.2 9.3 9.4 9.5 10 ACCEDER AUX INFORMATIONS DUNE FONCTION ......................................................................................52 ACCEDER AUX INFORMATIONS DUN CMDLET ...........................................................................................55 ACCEDER AUX INFORMATIONS DUN FICHIER SCRIPT ................................................................................56 ACCEDER AUX INFORMATIONS DUN MODULE ...........................................................................................56 UNE APPROCHE DU SCRIPTING BASEE SUR DES PLUG-INS ...........................................................................57

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 12

SCRIPTBLOCK ET ATTRIBUTS ................................................................................................................63 CONSTRUIRE LAIDE EN LIGNE..............................................................................................................64 12.1 CONSTRUIRE UN FICHIER DAIDE LOCALISE AU FORMAT MAML ..............................................................64

13 14

LIENS................................................................................................................................................................66 CONCLUSION.................................................................................................................................................67

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

Page 3 / 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 motscls spcifiques au contexte de dclaration dune fonction ou dun script.

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

Page 4 / 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")] $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 5 / 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
Function FcntAvance{ Param ( [Parameter(Position=0)] $NomParam, $Count) Write-host "`$NomParam=$NomParam `t `$Count=$Count reste=$args" }

On dclare un attribut au sein de la clause Param :

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 6 / 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 7 / 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 8 / 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 9 / 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 10 / 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 11 / 67

$NomParam=1 $NomParam=2 $NomParam=3 $NomParam=4

$Count=9 $Count=9 $Count=9 $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= process { Write-host "`$NomParam=$_ `t `$Count=$Count" } $Count=9

On doit utiliser $_ reprsentant lobjet courant dans le pipeline :

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 12 / 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 13 / 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 14 / 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 15 / 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 16 / 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 17 / 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 18 / 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 19 / 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 [Int]$Name #$Name ) 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 # cast implicite de lobjet String # cast implicite de lobjet Int # tout objet est accept

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 -------- -------- ---True True Int32

BaseType -------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 [Nom de paramtre] 4 True True Int32

System.ValueType

System.ValueType

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

Page 20 / 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 21 / 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 22 / 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 23 / 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 24 / 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 25 / 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 26 / 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" " " " " } TestValidation Paramtres valides $username -eq [string]::Empty : True $username -eq $null : False $Tab -eq [string]::Empty : False $Tab -eq $null : True `$username -eq [string]::Empty : $($username -eq [string]::Empty)" `$username -eq `$null : $($username -eq $null)" `$Tab -eq [string]::Empty : $($Tab -eq [string]::Empty)" `$Tab -eq `$null : $($Tab -eq $null)"

#$username=[string]::Empty #exception

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 27 / 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 28 / 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 29 / 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 30 / 67

TestValidation $ofs="" "$Chars".length TestValidation

$Chars

$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})$)] [String] $TriGram="ABC" # Mot de trois lettres

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 31 / 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 32 / 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 } 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 { $count }

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 33 / 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 34 / 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 35 / 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 36 / 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 37 / 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, Page 38 / 67

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

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 39 / 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 40 / 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 41 / 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 ---CommandOrigin CommandRuntime CurrentPSTransaction Events Host InvokeCommand InvokeProvider JobRepository MyInvocation ParameterSetName SessionState Stopping CurrentProviderLocation Dispose Equals GetDynamicParameters GetHashCode GetResolvedProviderPathFromPSPath GetResourceString GetType GetUnresolvedProviderPathFromPSPath GetVariableValue Invoke MemberType ---------Property Property Property Property Property Property Property Property Property Property Property Property Method Method Method Method Method Method Method Method Method Method Method

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

Page 42 / 67

ShouldContinue ShouldProcess ThrowTerminatingError ToString TransactionAvailable WriteCommandDetail WriteDebug WriteError WriteObject WriteProgress WriteVerbose WriteWarning

Method Method Method Method Method Method Method Method Method Method Method 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


Function FcntAvance{ [CmdletBinding()] Param ( [Parameter(ValueFromPipeline = $true)] $NomParam, $Count) Begin { $pscmdlet.WriteDebug("**** Test de log --------")

La variable $PSCmdlet permet galement de prciser les informations lies une exception :

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

Page 43 / 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 44 / 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
$ErrorView="CategoryView" FcntAvance un 9 OperationStopped: (Erreur: l'objet n'existe pas.:String) [], RuntimeException

Avec Throw :

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 45 / 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 46 / 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 47 / 67

Get-PSProvider Name ---WSMan FileSystem PscxSettings Capabilities -----------Credentials Filter, ShouldProcess None Drives -----{WSMan} {C, D } {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 48 / 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, [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 } Mandatory = $true, ValueFromPipeline = $true)] $ID,

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

Page 49 / 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 High

Description 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 50 / 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 Low None * High Medium High Medium * None High Low Pas de demande de confirmation automatique. Pas de demande de confirmation automatique. Aucune demande de confirmation. Mme si on prcise Confirm. Seule la prsence de Confirm dclenchera une demande de confirmation. Demande de confirmation automatique. 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 Le paramtre -WhatIf n'est pas activ automatiquement. (par dfaut) 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 51 / 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 52 / 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 --NomParam Count Verbose Debug ErrorAction WarningAction ErrorVariable WarningVariable OutVariable OutBuffer Value ----System.Management.Automation.ParameterMetadata System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata *System.Management.Automation.ParameterMetadata

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

Page 53 / 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 ParameterSetName :0 : __AllParameterSets

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

Page 54 / 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 ceuxci 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 55 / 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 &$Ci -Type Cmdlet Get-Item

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 56 / 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 ------------AsCustomObject Method ExportedAliases Property ExportedCmdlets Property ExportedFormatFiles Property ExportedFunctions Property ExportedTypeFiles Property ExportedVariables Property Guid Property Definition ---------psobject AsCustomObject() System.Collections.Generic.Dictionary`2[[System.String, System.Collections.Generic.Dictionary`2[[System.String, System.Collections.ObjectModel.ReadOnlyCollection`1[[System.String, System.Collections.Generic.Dictionary`2[[System.String, System.Collections.ObjectModel.ReadOnlyCollection`1[[System.String, System.Collections.Generic.Dictionary`2[[System.String, 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 57 / 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 GetItem :

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 58 / 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 59 / 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 60 / 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 61 / 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-commandswith-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 62 / 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 63 / 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 64 / 67

La

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 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 65 / 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 66 / 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 sousjacents 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 !

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

Page 67 / 67

Vous aimerez peut-être aussi