diatribe sur: j'étais même très, très en colère que l'on peut instancier un type de System.Management.Automation.ParameterMetadata mais nous ne pouvons pas initialisize il. Microsoft détruit beaucoup de joie de la bibliothèque de classe en contrant les classes par l'utilisation de privé ou interne ou scellé ...... ils l'utilisent souvent, et sans aucune raison pensable. C'est un design de bibliothèque très fou! rant off:
Pour la métaprogrammation et la création de ProxyCommands (fonctions proxy), j'ai eu besoin de créer un paramètre Windows PowerShell à partir de rien. Je n'aime même pas entrer dans les classes et voler et utiliser des trucs vorbidden, qui est sujet à changement. Même l'astuce de sérialisation est la même façon de faire la même chose sur un itinéraire différent.
Voici mon prototype de solution. Je crée une fonction avec un paramètre comme texte (fonction sourcecode). mon premier atempt était de faire une fonction New-Item: \ -value {code} dans le lecteur de fonction, puis faire un Get-Command à la nouvelle fonction pour extraire les métadonnées. Mais cela apparaît, que la fonction était un cheval de sorcecode mort seul. Ce n'était pas compilé. J'ai donc dû utiliser Invoke-Expression pour 'compiler' le code source de la fonction.
Function New-Parameter {
[CmdletBinding()]
param(
[Switch]$Mandatory,
[UInt32]$Position,
[Switch]$ValueFromPipeline,
[Switch]$ValueFromPipelineByPropertyName,
[Switch]$ValueFromRemainingArguments,
[String]$HelpMessage,
[Type]$Type=[Type]'System.Management.Automation.SwitchParameter',
[Parameter(Mandatory=$True)]
[String]$Name,
[String]$DefaultValue,
[Switch]$DontShow,
[String[]]$ParameterSetName,
[String[]]$Aliases,
# if Metadata is present the result is an System.Management.Automation.ParameterMetadata object
# If Metadata is absent the sourcecode for the Parameter is returned
[Switch]$Metadata
)
$ParameterAttrib = [System.Collections.ArrayList]@()
# using GUID to create an unique function Name
$Guid = ([Guid]::NewGuid()).ToString()
# using a StringBuilder to glue the sourcecode
$stringBuilder = New-Object System.Text.StringBuilder
If($Metadata.IsPresent) {
# Open the Function{} block
[Void]$stringBuilder.AppendLine("Function $Guid {")
# add the [CmdletBinding()] attribute
[Void]$stringBuilder.AppendLine("[CmdletBinding()]")
# Open the Param() block
[Void]$stringBuilder.AppendLine("param(")
}
# query if we have one or more ParameterSetName
$ParmameterSetNameCount = 0
If(-not [String]::IsNullOrEmpty($ParameterSetName)) {
$ParmameterSetNameCount = @($ParameterSetName).Count
}
# Open the [Parameter()] attribut
[Void]$stringBuilder.Append('[Parameter(')
If($Mandatory.IsPresent) {
[Void]$ParameterAttrib.Add('Mandatory=$True')
}
If($Position) {
[Void]$ParameterAttrib.Add("Position=$Position")
}
If($ParmameterSetNameCount -gt 0){
# in the first full blown [Parameter()] attribut allways insert the first ParametersetName
[Void]$ParameterAttrib.Add("ParameterSetName='$($ParameterSetName[0])'")
}
If($ValueFromPipeline.IsPresent) {
[Void]$ParameterAttrib.Add('ValueFromPipeline=$True')
}
If($ValueFromPipelineByPropertyName.IsPresent) {
[Void]$ParameterAttrib.Add('ValueFromPipelineByPropertyName=$True')
}
If($ValueFromRemainingArguments.IsPresent) {
[Void]$ParameterAttrib.Add('ValueFromRemainingArguments=$True')
}
If($DontShow.IsPresent) {
If($PSVersionTable.PSVersion.Major -lt 4) {
Write-Warning "The 'DontShow' attribute requires PowerShell 4.0 or above! `n Supressing the 'DontShow' attribute!"
} Else {
[Void]$ParameterAttrib.Add('DontShow')
}
}
If(-not [String]::IsNullOrEmpty($HelpMessage)) {
[Void]$ParameterAttrib.Add("HelpMessage='$HelpMessage'")
}
# generate comma separated list from array
[Void]$stringBuilder.Append("$($ParameterAttrib -Join ',')")
$ParameterAttrib.Clear()
# close the [Parameter()] attribut
[Void]$stringBuilder.AppendLine(")]")
$ParmameterSetLoopCounter++
# If we have more then one ParametersetName
IF($ParmameterSetNameCount -gt 1) {
# add remaining parameterset names the parameter belongs to
for ($i = 1; $i -lt $ParmameterSetNameCount; $i++) {
[Void]$stringBuilder.AppendLine("[Parameter(ParameterSetName='$($ParameterSetName[$i])')]")
}
}
# Create Alias Attribute from Aliases
If(-not [String]::IsNullOrEmpty($Aliases)) {
[Void]$stringBuilder.AppendLine("[Alias('$($Aliases -join "','")')]")
}
# add Parameter Type
[Void]$stringBuilder.Append("[$($Type.Fullname)]")
# add the Parameter Name
[Void]$stringBuilder.Append("`$$Name")
If(-not [String]::IsNullOrEmpty($ParameterSetName)) {
[Void]$stringBuilder.Append("=$DefaultValue")
}
If($Metadata.IsPresent) {
# close the Param() block
[Void]$stringBuilder.AppendLine()
[Void]$stringBuilder.AppendLine(')')
# close the Function block
[Void]$stringBuilder.AppendLine('}')
}
# return the result
If($Metadata.IsPresent) {
# if we have to return a ParameterMetadata Object we create a temporary function
# because you can instatiate a ParameterMetadata Object but most of the Properties are constrained to get only and not to set!
# Create and 'compile' the function into the function: drive
Invoke-Expression ($stringBuilder.ToString())
# from the temporary function we query the the ParameterMetadata and
# return theParameterMetadata Object
(Get-Command -Name $Guid -CommandType Function).Parameters.$Name
# remove the Function from Function: drive
$Null = Remove-Item Function:\$Guid -Force
} Else {
# return the sourcecode of the Parameter
Write-Output $stringBuilder.ToString()
}
}
#Example calls:
# without Parametersets
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34 -Metadata
# with Parametersets
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -ParameterSetName 'Snover','Payette' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34
New-Parameter -Name 'Param1' -Mandatory -Position 3 -ValueFromPipeline -ValueFromPipelineByPropertyName -ValueFromRemainingArguments -HelpMessage "Give me hope Joana!" -Type 'System.String' -ParameterSetName 'Snover','Payette' -Aliases 'Ali1','Ali2','Ali3' -DontShow -DefaultValue 34 -Metadata
que je fais DROIT DE CONSTRUIRE LES PARAMETERSETS?
Tout d'abord, merci pour la réponse, mais en utilisant 'OutVariable' pour copier les informations du jeu de paramètres à partir d'une erreur - Impossible d'indexer dans un tableau nul. À la ligne: 25 ombles: 55. + $ MetaData.Parameters [ 'OutVariable'] [ParameterSets <<<< '__AllParameterSets']) + CategoryInfo: InvalidOperation: (__AllParameterSets: String) [], RuntimeException + FullyQualifiedErrorId: NullArray Si j'essaie d'utiliser mon paramètre précédent, j'obtiens des informations différentes dans la propriété d'attribut et la propriété de jeu de paramètres. Les informations de la propriété de jeu de paramètres sont les scripts générés. –
Oui, vous ne pouvez pas modifier le jeu de paramètres, ou bien cela change l'endroit d'où vous l'avez obtenu. Oubliez ça, essayez cette nouvelle méthode de réflexion. Je ne peux pas croire qu'il n'y a aucun moyen de créer cette classe. – Jaykul
Oui, j'étais surpris qu'il n'y avait pas de constructeur pour ça. Merci pour la solution de contournement. –