我不确定是否可以这样做,所以首先要解释我想要发生的事情。
我的PowerShell模块函数有这个参数
[ValidateScript({ Test-Path $_ -PathType Leaf })][ValidatePattern("\.xml$")][parameter(Mandatory = $true)][string[]]$PolicyPaths,
它接受多个
.xml
文件。
我一直在使用这个论证完成者:
$ArgumentCompleterPolicyPaths = {
Get-ChildItem | where-object { $_.extension -like '*.xml' } | foreach-object { return "`"$_`"" }
}
Register-ArgumentCompleter -CommandName "Deploy-SignedWDACConfig" -ParameterName "PolicyPaths" -ScriptBlock $ArgumentCompleterPolicyPaths
一直工作正常。现在我想改进它,以便当我需要从当前工作目录中选择多个
.xml
文件时,并通过按 Tab 开始选择它们(因为我不知道文件名而无需键入任何内容),建议的文件不会'包含我已经选择的那些。我选择它们的方法是先按 Tab 键,然后在每个选定的文件后添加一个逗号,
,然后再次按 Tab 键从建议中选择另一个。
我尝试了 2 个新的参数完成器,但没有一个按照我想要的方式工作。
这是第一个:
$ArgumentCompleterPolicyPaths = {
# Get the current command and the already bound parameters
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
# Get the xml files in the current directory
Get-ChildItem | Where-Object { $_.Extension -like '*.xml' } | ForEach-Object {
# Check if the file is already selected
if ($fakeBoundParameters.PolicyPaths -notcontains $_.FullName) {
# Return the file name with quotes
return "`"$_`""
}
}
}
Register-ArgumentCompleter -CommandName "Deploy-SignedWDACConfig" -ParameterName "PolicyPaths" -ScriptBlock $ArgumentCompleterPolicyPaths
这是第二个:
# Define a class that inherits from ArgumentCompleterAttribute
class XmlFileCompleter : ArgumentCompleterAttribute {
# Override the GetArgumentCompletionSuggestions method
[System.Collections.Generic.IEnumerable[System.Management.Automation.CompletionResult]] GetArgumentCompletionSuggestions(
[System.Management.Automation.CommandAst]$commandAst,
[System.Management.Automation.CommandParameterAst]$parameterAst,
[System.Collections.IDictionary]$fakeBoundParameters,
[System.Management.Automation.Language.IScriptPosition]$cursorPosition
) {
# Get all XML files in the current directory
$xmlFiles = Get-ChildItem -Path . -Filter *.xml
# Filter out the files that have already been selected
$xmlFiles = $xmlFiles | Where-Object { $fakeBoundParameters[$parameterAst.ParameterName] -notcontains $_.Name }
# Return the file names as completion results
foreach ($xmlFile in $xmlFiles) {
[System.Management.Automation.CompletionResult]::new($xmlFile.Name, $xmlFile.Name, 'ParameterValue', $xmlFile.Name)
}
}
}
最后在 VS 代码中抛出这个错误:
Unable to find type [ArgumentCompleterAttribute].
P.S 这是我的参数选项卡完成器的当前行为,看看它如何建议我已经选择的相同文件: https://1drv.ms/u/s!AtCaUNAJbbvIhupw8-67jn6ScaBOGw?e=a35FoG
它是 APNG 文件,所以只需将其拖放到浏览器上即可。
问题是临时绑定参数的字典
$fakeBoundParameters
只包含有关other参数的信息如果您还没有键入要完成的非初始数组元素的前缀.
也就是说,使用
el1
和 el2
表示先前键入/tab 完成的数组元素,在 el1, el2,
之后按 Tab会导致手头的参数 not 作为条目包含在
$fakeBoundParameters
中,所以 el1
和 el2
值不能那样检查。
$fakeBoundParameter
字典的错误/设计限制,至少达到 PowerShell 7.4.0-preview.3:语法不完整 表达式,例如 el1, el2,
似乎阻止包含目前提供的数组元素;请参阅GitHub 问题 #17975因此,对于在新元素的开头没有键入至少一个字符的情况下用制表符完成的数组参数,先前键入/完成的任何数组元素实际上不反映在
$fakeBoundParameters
中。
workaround是在
$commandAst
完成脚本块中搜索传递的命令AST,以查找以.xml
结尾的字符串常量表达式,如下所示:
.xml
Register-ArgumentCompleter `
-CommandName Deploy-SignedWDACConfig `
-ParameterName PolicyPaths `
-ScriptBlock {
# Get the current command and the already bound parameters
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
# Find all string constants in the AST that end in ".xml"
$existing = $commandAst.FindAll({
$args[0] -is [System.Management.Automation.Language.StringConstantExpressionAst] -and
$args[0].Value -like '*.xml'
},
$false
).Value
# Get the xml files in the current directory
Get-ChildItem -Filter *.xml | ForEach-Object {
# Check if the file is already selected
if ($_.FullName -notin $existing) {
# Return the file name with quotes
"`"$_`""
}
}
}
ArgumentCompleterAttribute
:
定义中使用full 类型名称作为基类名称,
System.Management.Automation.ArgumentCompleterAttribute
Attribute
后缀,即ArgumentCompleter
does似乎在没有名称空间限定符的情况下工作。也就是说,您可以简单地直接使用它,而不是
子类这个
ArgumentCompleter
,传递与Register-ArgumentCompleter
一起使用的相同脚本块作为属性;也就是说,在您的 Deploy-SignedWDACConfig
命令中,您可以使用 $PolicyPaths
.修饰
[ArgumentCompleter({ ... })]
参数声明
当您使用 tab-completion 为具有
ArgumentCompleter
属性的参数选择值时,PowerShell 会将所选值存储在名为 $LASTCOMPLETION
的变量中。 $LASTCOMPLETION
变量是一个自动变量,它包含在 tab-completion 期间选择的最新值。但是 $LASTCOMPLETION
变量可能并不总是可靠的,在某些情况下,它可能包含过时或不正确的值。要解决此问题,您可以使用 $ExecutionContext.SessionState.PSVariable
属性访问 lastCompletionResult
变量,这是另一个自动变量,它还包含在 tab-completion 期间选择的最新值:
[parameter(Mandatory = $true)]
[ArgumentCompleter({
$exclude = $ExecutionContext.SessionState.PSVariable.GetValue("lastCompletionResult") | Where-Object { $_ -ne $PolicyPaths }
Get-ChildItem -File -Filter *.xml | Where-Object { $_.Name -notin $exclude } | % Name
})]
[string[]]$PolicyPaths