如何阻止PowerShell ValidateSet参数补全器重复建议已选值?
WDAC策略参数补全去重与验证实现方案
问题背景
为Remove-WDACConfig cmdlet的PolicyIDs和PolicyNames参数实现了基于IValidateSetValuesGenerator类的验证与补全,但补全时会重复建议已选中的值,需要在保留验证功能的同时,让补全器只显示未选中的选项。
解决方案
由于IValidateSetValuesGenerator无法访问已输入的参数值,因此采用保留ValidateSet验证+自定义ArgumentCompleter补全的组合方案:通过原有的验证类确保输入合法性,用自定义补全逻辑过滤已选值。
1. 保留验证类(用于ValidateSet验证)
# PolicyNames参数的ValidateSet验证类 Class PolicyNamez : System.Management.Automation.IValidateSetValuesGenerator { [string[]] GetValidValues() { return ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.IsSystemPolicy -ne "True" }).Friendlyname } } # PolicyIDs参数的ValidateSet验证类 Class PolicyIDz : System.Management.Automation.IValidateSetValuesGenerator { [string[]] GetValidValues() { return ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.IsSystemPolicy -ne "True" }).policyID } }
2. Cmdlet参数定义(保留原ValidateSet配置)
function Remove-WDACConfig { [CmdletBinding(DefaultParameterSetName = "Default")] param( [Parameter(Mandatory = $true, ParameterSetName = "Remove Policies")] [switch]$RemovePolicies, [ValidateSet([PolicyIDz])] [Parameter(Mandatory = $false, ParameterSetName = "Remove Policies")] [string[]]$PolicyIDs, [ValidateSet([PolicyNamez])] [Parameter(Mandatory = $false, ParameterSetName = "Remove Policies")] [string[]]$PolicyNames ) # 此处添加你的cmdlet核心逻辑 }
3. 添加自定义参数补全器(实现去重)
# 为PolicyIDs配置去重补全 Register-ArgumentCompleter -CommandName Remove-WDACConfig -ParameterName PolicyIDs -ScriptBlock { param($wordToComplete, $commandAst, $cursorPosition) # 解析已输入的PolicyIDs值 $selectedIDs = $commandAst.FindAll({ $args[0] -is [System.Management.Automation.Language.ParameterAst] -and $args[0].ParameterName -eq 'PolicyIDs' }, $false) | ForEach-Object { $_.Arguments.Extent.Text -replace '["'']', '' -split ',' | Where-Object { $_ -match '\S' } } # 获取所有可用策略ID,过滤已选值 $allIDs = ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.IsSystemPolicy -ne "True" }).policyID $availableIDs = $allIDs | Where-Object { $_ -notin $selectedIDs } # 生成补全结果 $availableIDs | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } # 为PolicyNames配置去重补全(兼容带空格的名称) Register-ArgumentCompleter -CommandName Remove-WDACConfig -ParameterName PolicyNames -ScriptBlock { param($wordToComplete, $commandAst, $cursorPosition) # 解析已输入的PolicyNames值 $selectedNames = $commandAst.FindAll({ $args[0] -is [System.Management.Automation.Language.ParameterAst] -and $args[0].ParameterName -eq 'PolicyNames' }, $false) | ForEach-Object { $_.Arguments.Extent.Text -replace '["'']', '' -split ',' | Where-Object { $_ -match '\S' } } # 获取所有可用策略名称,过滤已选值 $allNames = ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_ -isSystemPolicy -ne "True" }).Friendlyname $availableNames = $allNames | Where-Object { $_ -notin $selectedNames } # 生成带引号的补全结果(处理含空格的名称) $availableNames | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new("`"$_`"", $_, 'ParameterValue', $_) } }
关键说明
- 验证逻辑保留:原有的
ValidateSet验证仍然生效,确保输入的策略ID/名称均为合法值。 - 补全去重:自定义补全器通过解析命令语法树获取已输入的参数值,过滤后只显示未选中的选项。
- 兼容特殊名称:策略名称含空格时,补全结果自动添加双引号,避免PowerShell解析错误。
- 版本适配:支持PowerShell 7.4,利用
CommandAst实现参数值解析。
内容的提问来源于stack exchange,提问作者SpyNet
相关产品推荐
相关产品推荐

