разглагольствовать на: Я даже очень, очень зол, что мы можем создать экземпляр Тип System.Management.Automation.ParameterMetadata, но мы не можем initialisize его. Microsoft разрушает много радости в библиотеке классов, преследуя классы с помощью частных или внутренних или запечатанных ... они используют его часто и без какой-либо мыслимой причины. Это очень дизайн библиотеки орехов! rant off:
Для метапрограммирования и создания ProxyCommands (прокси-функций) мне потребовалось создать параметр PowerShell Windows программно с нуля. Я даже не люблю врываться в классы и воровать и использовать vorbidden вещи, которые могут быть изменены. Даже трюк сериализации - это тот же грязный способ сделать то же самое на другом маршруте.
вот мой прототип решения. Я создаю функцию с параметром как текст (function sourcecode). Моей первой задачей было сделать функцию нового элемента: \ -value {code} в драйвере функций, а затем сделать Get-Command для новой функции для извлечения метаданных. Но это свидетельствует о том, что функция была мертвым sorcecode только лошади. Его не скомпилировали. Поэтому мне пришлось использовать Invoke-Expression для «компиляции» исходного кода функции.
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
я делаю ПРАВО Постройте PARAMETERSETS?
Во-первых, спасибо за ответ, однако используя «OutVariable», чтобы скопировать информацию о параметрах из числа ошибок - Невозможно индексировать нулевой массив. В строке: 25 символ: 55. + $ MetaData.Parameters [ 'OutVariable'] ParameterSets [<<<< '__AllParameterSets']) + CategoryInfo: InvalidOperation: (__AllParameterSets: String) [], RuntimeException + FullyQualifiedErrorId: NullArray Если я попытаюсь использовать мой предыдущий параметр, я получаю различную информацию в свойстве атрибута и свойстве набора параметров. Информация из свойства набора параметров - это сценарий. –
Да, вы не можете изменить набор параметров, иначе он изменит место, из которого вы его получили. Забудьте об этом, попробуйте этот новый метод отражения. Не могу поверить, что создать этот класс невозможно. – Jaykul
Да, я был удивлен, что для этого не было конструктора. Спасибо за обходной путь. –