问题描述
我正在寻找一种方法来制作一个 cmdlet,该 cmdlet 接收参数并在输入时提示从预定义的选项数组中完成的建议。
我正在尝试这样的事情:
$vf = @('Veg','Fruit')
function Test-ArgumentCompleter {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[validateset($vf)]
$Arg
)
}
预期的结果应该是:
编写“Test-ArgumentCompleter F”时,单击 tub 按钮后,F 自动完成为 Fruit。
解决方法
PowerShell 通常要求属性是文字(例如,
'Veg'
)或常量(例如,$true
)。-
动态功能需要使用 script block(本身指定为 文字、
{ ... }
)或在特定情况下使用 type literal。 -
但是,
[ValidateSet()]
属性只接受字符串(按需化)文字数组或 - 在 PowerShell (Core) v6 及更高版本 - 一个 输入文字(见下文)。
更新:
-
如果您使用 PowerShell (Core) v6+,则有一个更简单的解决方案,它基于定义实现 的 custom
class
System.Management.Automation.IValidateSetValuesGenerator
界面 - 请参阅 iRon's helpful answer 中的第二个解决方案。 -
即使在 Windows PowerShell 中,一个更简单的解决方案也是可能的,如果您的验证值可以定义为
enum
type - 见Mathias R. Jessen's helpful answer。
要获得基于
-
[ArgumentCompleter()]
用于动态制表符补全。 -
[ValidateScript()]
用于确保在命令提交时参数确实是数组中的一个值,使用 脚本块。
# The array to use for tab-completion and validation.
[string[]] $vf = 'Veg','Fruit'
function Test-ArgumentCompleter {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
# Tab-complete based on array $vf
[ArgumentCompleter(
{ param($cmd,$param,$wordToComplete) $vf -like "$wordToComplete*" }
)]
# Validate based on array $vf.
# NOTE: If validation fails,the (default) error message is unhelpful.
# Unfortunately,this cannot be helped in *Windows PowerShell*,but in
# PowerShell (Core) 7+,you can add an `ErrorMessage` property:
# [ValidateScript({ $_ -in $vf },ErrorMessage = 'Unknown value: {0}')]
[ValidateScript( { $_ -in $vf })]
$Arg
)
"Arg passed: $Arg"
}
,
补充@mklement0和@Mathias的答案,使用dynamic parameters:
$vf = 'Veg','Fruit'
function Test-ArgumentCompleter {
[CmdletBinding()]
param ()
DynamicParam {
$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute.Mandatory = $true
$AttributeCollection.Add($ParameterAttribute)
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($vf)
$AttributeCollection.Add($ValidateSetAttribute)
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter('Arg',[string],$AttributeCollection)
$RuntimeParameterDictionary.Add('Arg',$RuntimeParameter)
return $RuntimeParameterDictionary
}
}
根据您希望如何预定义参数值,您还可以使用 dynamic validateSet values:
Class vfValues : System.Management.Automation.IValidateSetValuesGenerator {
[String[]] GetValidValues() { return 'Veg','Fruit' }
}
function Test-ArgumentCompleter {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[ValidateSet([vfValues])]$Arg
)
}
注意: PowerShell 6.0 中引入了 IValidateSetValuesGenerator
类 [read: interface]
除了 mklement0's excellent answer 之外,我觉得有必要指出,在第 5 版及更高版本中,您有一个稍微简单的替代方案:enum
的
enum
或“枚举类型”是与底层整数值(数字)关联的标签(字符串)的静态列表 - 通过将参数限制为枚举类型,PowerShell 将自动针对它验证输入值并提供参数补全:
enum MyParameterType
{
Veg
Fruit
}
function Test-ArgumentCompleter {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[MyParameterType]$Arg
)
}
尝试用 tab 完成 -Arg
的参数现在将循环抛出匹配的 MyParameterType
的有效枚举标签:
PS ~> Test-ArgumentCompleter -Arg v[<TAB>]
# gives you
PS ~> Test-ArgumentCompleter -Arg Veg
,
为了添加其他有用的答案,我使用了与我为工作编写的脚本类似的东西:
nil
Register-ArgumentCompleter 的文档在 Microsoft Docs 中有很好的解释。我个人不喜欢使用 $vf = @('Veg','Fruit','Apple','orange')
$ScriptBlock = {
Foreach($v in $vf){
New-Object -Type System.Management.Automation.CompletionResult -ArgumentList $v,$v,"ParameterValue","This is the description for $v"
}
}
Register-ArgumentCompleter -CommandName Test-ArgumentCompleter -ParameterName Arg -ScriptBlock $ScriptBlock
function Test-ArgumentCompleter {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[String]$Arg )
}
语句,因为它不允许我在智能感知中使用 空格; enum
参数与添加描述的功能相同。
输出:
编辑:
@Mklement 在验证提供给参数的参数方面做得很好。如果不使用更多的 powershell 逻辑来为您进行验证(不幸的是,它会在函数体中完成),仅此一项就不允许您这样做。
Validate