salut,
Ce matin en regardant le site powershell-scripting.com je me suis aperçu que Laurent a des contributions, l'une d'elles est la création de "directives conditionnelles", alors je mes suis dis: "tiens c'est une bonne idée ça !" alors je me suis inspiré de son dernier topic pour créer une fonction se basant sur les directives...et tant qu'on y est... je vais copiez son intro
<DEBUT_COPIE>
le principe est de délimiter une ou plusieurs lignes de code par un mot clé de début de directive et
un mot clé de fin de directive...
<FIN_COPIE>
le mot clé de debut étant <#DynParam et le mot clé de fin est Dynparam#>
malheureusement on ne trouve pas beaucoup de documentation au sujet des paramètres dynamiques, alors on va commencer par différencier les paramètres dynamiques des paramètres statiques:
les paramètres statiques:
ils sont parser avant l'execution du code 'parse time'
ils ne permettent pas de voir les autres paramètres dans le script ou dans la fonction
ils sont visible dans le systeme d'aide (get-help)
les paramètres dynamiques:
ils sont parser dynamiquement à la volée 'runtime'
ils peuvent voir les autres paramètres
ils ne sont pas visibles dans le systeme d'aide (get-help)
pour voir les cmdlets qui ont des paramètres dynamiques:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 :exitfor foreach($cmd in Get-Command -CommandType cmdlet) { foreach($param in $cmd.ParameterSets | select -Expand parameters) { if($param.IsDynamic) { New-Object psobject -Property @{ Command = $cmd Provider = $PWD.Provider.Name } continue exitfor } } }pour voir ces paramètres dans chaque psprovider vous pouvez utiliser ce bout de code dans chaque psprovider:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 Provider Command -------- ------- FileSystem Add-Content FileSystem Get-Content FileSystem Set-Content
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 foreach($cmd in Get-Command -CommandType cmdlet) { $array=@() foreach($param in $cmd.ParameterSets | select -ExpandProperty parameters) { if($param.IsDynamic) { $array+=$param.name } } if($array) { new-object psobject -Property @{ Command = $cmd.name DynamicParameter = $array | select -Unique Provider = $PWD.Provider.Name } } }revenons maintenant à notre fonction:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 DynamicParameter Provider Command ---------------- -------- ------- Encoding FileSystem Add-Content {Delimiter, Wait, Encod... FileSystem Get-Content Encoding FileSystem Set-Content
vous verrez que le principe est simple, mais comment ça marche ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 ################################################################################################# # # Description: # Converti une directive de création de paramètres dynamique en # code .NET # # Version: # 1.0 # # Auteur: # Walid Toumi # # Blog: # http://walid-toumi.blogspot.com/ # # NOTE: # 1) pour le moment cette version ne s'utilise qu'avec ISE, vous pouvez copier votre fonction à convertir # dans le volet de script courant puis appelez la fonction 'ConvertTo-DynamicParam' # # 2) cette fonction n'est pas complète donc à ne pas utiliser dans des environements de production # ###################################################{############################################# function ConvertTo-DynamicParam { if([string]::IsNullOrEmpty($psise)) { throw 'cette fonction requiert "ISE"' } $dp='' $content = $psISE.CurrentFile.Editor.Text # $content = [IO.FILE]::ReadAllText((join-path $pwd .\testdyn.ps1)) $dyncomm = @([management.automation.psparser]::Tokenize($content,[ref]$null) | Where { $_.Type -eq 'comment' -and $_.Content -match '<#Dynparam' })[0].Content -replace '<#Dynparam.*|Dynparam#>' $tmpfunc = Set-Item -Path function:dummyfunc -Value $dyncomm -PassThru Remove-Item function:dummyfunc -Force $commun=[Management.Automation.Internal.CommonParameters].GetProperties() | foreach { $_.Name } $params=@($tmpfunc.Parameters.GetEnumerator() | ? { $commun -notcontains $_.key }) $ParameterName = $params[0].Value.Name $aliases = @($params[0].value.Aliases) $attr = $params[0].Value.attributes | Where { $_.TypeId -like '*ParameterAttribute' } $vals = $params[0].Value.Attributes | Where { $_.TypeId -notmatch 'ParameterAttribute|ArgumentTypeConverterAttribute' } $Mandatory = $attr.Mandatory $ParameterSetName=$attr.ParameterSetName $Position=$attr.Position $ByValue=$attr.ValueFromPipeline $ByPropertyName=$attr.ValueFromPipelineByPropertyName $RemainingArgs=$attr.ValueFromRemainingArguments $Type=$params[0].value.ParameterType.fullname $dp+=@" DynamicParam { `n #if(une condition) { `$Attributes = New-Object 'Management.Automation.ParameterAttribute' `$Attributes.ParameterSetName = '$ParameterSetName' `$Attributes.Mandatory = `$$Mandatory `$Attributes.Position = $Position `$Attributes.ValueFromPipeline = `$$ByValue `$Attributes.ValueFromPipelineByPropertyName = `$$ByPropertyName `$Attributes.ValueFromRemainingArguments = `$$RemainingArgs `$Attributes.HelpMessage = '$helpMessage ' `$AttributeCollection = New-Object 'Collections.ObjectModel.Collection[Attribute]' `$AttributeCollection.Add(`$Attributes) `n "@ if($aliases) { $dp+=@" `$Attribute=new-object 'System.Management.Automation.AliasAttribute' $($aliases -join ',') `$attributeCollection.Add(`$Attribute) `n "@ } # attributs de validation if($Vals) { foreach($Val in $Vals) { Switch ($val.TypeId.Name) { 'ValidateScriptAttribute' { $dp+=@" `$Attribute=new-object 'Management.Automation.ValidateScriptAttribute' {`$$($Val.ScriptBlock)} `$attributeCollection.Add(`$Attribute) `n "@ } 'ValidatePatternAttribute' { $dp+=@" `$Attribute=new-object 'Management.Automation.ValidatePatternAttribute' '$($Val.RegexPattern)' `$attributeCollection.Add(`$Attribute) `n "@ } 'ValidateSetAttribute' { $dp+=@" `$Attribute = new-object System.Management.Automation.ValidateSetAttribute $($Val.ValidValues -join ',') `$attributeCollection.Add(`$Attribute) `n "@ } 'ValidateLengthAttribute' { $dp+=@" `$Attribute = new-object System.Management.Automation.ValidateLengthAttribute $($Val.MinLength,$Val.MaxLength -join ',') `$attributeCollection.Add(`$Attribute) `n "@ } 'ValidateCountAttribute' { $dp+=@" `$Attribute = new-object System.Management.Automation.ValidateCountAttribute $($Val.MinLength,$Val.MaxLength -join ',') `$attributeCollection.Add(`$Attribute) `n "@ } 'ValidateRangeAttribute' { $dp+=@" `$Attribute = new-object System.Management.Automation.ValidateRangeAttribute $($Val.MinRange,$Val.MaxRange -join ',') `$attributeCollection.Add(`$Attribute) `n "@ } 'ValidateNotNullOrEmptyAttribute' { $dp+=@" `$Attribute = new-object System.Management.Automation.ValidateNotNullOrEmptyAttribute `$attributeCollection.Add(`$Attribute) `n "@ } 'AllowEmptyCollectionAttribute' { $dp+=@" `$Attribute = new-object System.Management.Automation.AllowEmptyCollectionAttribute `$attributeCollection.Add(`$Attribute) `n "@ } 'AllowEmptyStringAttribute' { $dp+=@" `$Attribute = new-object System.Management.Automation.AllowEmptyStringAttribute `$attributeCollection.Add(`$Attribute) `n "@ } } #switch }#foreach vals }#if $dp+=@" `$MyParam = @{ Typ = 'Management.Automation.RuntimeDefinedParameter' Arg = @( '$ParameterName' '$Type' ,`$AttributeCollection ) } `$DynamicParam = New-Object @MyParam `$ParamDict = New-Object 'Management.Automation.RuntimeDefinedParameterDictionary' `$ParamDict.Add("$ParameterName", `$DynamicParam) `$ParamDict # endif condition } # vous pouvez testez la présence du paramètre dans le corps de la fonction dynamque par: # # if(`$PSBoundParameters.ContainsKey('$ParameterName')) { # // votre code ici # // vous pouvez utiliser votre variable dynamique comme ceci: `$PSBoundParameters.$ParameterName # } }`n "@ $tmpfile = ([IO.Path]::GetTempFileName()) + '.ps1' [regex]::Replace($content,'(?si)<#DynParam.+?DynParam#>',$dp) | Out-File $tmpfile -Force ise $tmpfile write-host "la fonction converti est dans le fichier: $tmpfile" -ForegroundColor green }
on met notre fonction dans le volet de script de 'ISE' et on appel notre convertTo-DynamicParam,
celle-ci va traduire notre 'code Powershell' en du code '.NET' et va créer un fichier dans le 'TEMP'
contenant notre fonction transformé..
voici un exemple d'utilisation:
on créer une simple fonction, ou disant le corps de notre fonction:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 function get-simple { [cmdletBinding()] param( [parameter(mandatory=$true)] [string]$String ) End { } }
maintenant on créer nos directives et une clause PARAM qui contiendra notre paramètre dynamique:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 function get-simple { [cmdletBinding()] param( [parameter(mandatory=$true)] [string]$String ) <#DynParam param( [parameter()] [Switch]$Reverse ) DynParam#> End { } }
maintenant on copie notre fonction dans ISE, on appel la fonction 'convertTo-DynamicParam' un autre
volet va s'afficher contenant ce code:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 function get-simple { [cmdletBinding()] param( [parameter(mandatory=$true)] [string]$String ) DynamicParam { #if(une condition) { $Attributes = New-Object 'Management.Automation.ParameterAttribute' $Attributes.ParameterSetName = '__AllParameterSets' $Attributes.Mandatory = $False $Attributes.Position = -2147483648 $Attributes.ValueFromPipeline = $False $Attributes.ValueFromPipelineByPropertyName = $False $Attributes.ValueFromRemainingArguments = $False $Attributes.HelpMessage = ' ' $AttributeCollection = New-Object 'Collections.ObjectModel.Collection[Attribute]' $AttributeCollection.Add($Attributes) $MyParam = @{ Typ = 'Management.Automation.RuntimeDefinedParameter' Arg = @( 'Reverse' 'System.Management.Automation.SwitchParameter' ,$AttributeCollection ) } $DynamicParam = New-Object @MyParam $ParamDict = New-Object 'Management.Automation.RuntimeDefinedParameterDictionary' $ParamDict.Add("Reverse", $DynamicParam) $ParamDict # endif condition } # vous pouvez testez la présence du paramètre dans le corps de la fonction dynamque par: # # if($PSBoundParameters.ContainsKey('Reverse')) { # // votre code ici # // vous pouvez utiliser votre variable dynamique comme ceci: $PSBoundParameters.Reverse # } } End { } }
on décommente if(condition) { et endif condition } et met l'instruction qu'on veux, par exemple:
ensuite, dans le corps de notre fonction (dans notre cas la partie "END") on teste la présence de notre switch $Reverse:
Code : Sélectionner tout - Visualiser dans une fenêtre à part if($String -notmatch '\d') {
puis on écris notre code, par exemple:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 End { if($PSBoundParameters.ContainsKey('Reverse')) { } }
et c'est tout:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 End { if($PSBoundParameters.ContainsKey('Reverse')) { return -join [regex]::Matches($String,".",'RightToLeft') } $String }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 function get-simple { [cmdletBinding()] param( [parameter(mandatory=$true)] [string]$String ) DynamicParam { if($String -notmatch '\d') { $Attributes = New-Object 'Management.Automation.ParameterAttribute' $Attributes.ParameterSetName = '__AllParameterSets' $Attributes.Mandatory = $False $Attributes.Position = -2147483648 $Attributes.ValueFromPipeline = $False $Attributes.ValueFromPipelineByPropertyName = $False $Attributes.ValueFromRemainingArguments = $False $Attributes.HelpMessage = ' ' $AttributeCollection = New-Object 'Collections.ObjectModel.Collection[Attribute]' $AttributeCollection.Add($Attributes) $MyParameter = @{ TypeName = 'Management.Automation.RuntimeDefinedParameter' ArgumentList = @( 'Reverse' 'System.Management.Automation.SwitchParameter' ,$AttributeCollection ) } $Dynamic = New-Object @MyParameter $ParamDictionary = New-Object 'Management.Automation.RuntimeDefinedParameterDictionary' $ParamDictionary.Add("Reverse", $Dynamic) $ParamDictionary } # dans le corps de la fonction vous pouvez testez la présence du paramètres # dynamque par: # # if($PSBoundParameters.ContainsKey('Reverse')) { # // votre code # // vous pouvez utiliser votre variable dynamique ainsi: $PSBoundParameters.Reverse # } } End { if($PSBoundParameters.ContainsKey('Reverse')) { return -join [regex]::Matches($String,".",'RightToLeft') } $String } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 PS II> get-simple 'string 23' -Reverse # ERREUR PS II> get-simple "developpez.com" -Reverse moc.zeppoleved
Partager