如何防止 PowerShell validateSet 参数完成器建议已选择的相同值?

问题描述 投票:0回答:1

我的 2 个 PowerShell 模块的参数.

有 2 个基于类的参数完成器/验证集
[ValidateSet([PolicyIDz])][parameter(Mandatory = $false, ParameterSetName = "Remove Policies")][string[]]$PolicyIDs,
[ValidateSet([PolicyNamez])][parameter(Mandatory = $false, ParameterSetName = "Remove Policies")][string[]]$PolicyNames,
# argument tab auto-completion and ValidateSet for Policy names 
Class PolicyNamez : System.Management.Automation.IValidateSetValuesGenerator {
    [string[]] GetValidValues() {
        $PolicyNamez = ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.IsSystemPolicy -ne "True" }).Friendlyname
           
        return [string[]]$PolicyNamez
    }
}   
    
# argument tab auto-completion and ValidateSet for Policy IDs     
Class PolicyIDz : System.Management.Automation.IValidateSetValuesGenerator {
    [string[]] GetValidValues() {
        $PolicyIDz = ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.IsSystemPolicy -ne "True" }).policyID
           
        return [string[]]$PolicyIDz
    }
}

它们用于 Windows Defender 应用程序控制,如果你想尝试它,你至少需要 Windows 11 22H2,它内置了 CITool

我想为每个参数都设置验证集和参数完成,最重要的是,防止参数完成者建议我已经选择的相同值。我正在使用最新的 PowerShell 7.4 版本。 这两个参数都用在同一个 cmdlet 中。

Remove-WDACConfig [-RemovePolicies] [-PolicyIDs <String[]>] [-PolicyNames <String[]>]

这个问题与我之前问过的另一个问题有关(并得到了答案)


这是我正在努力改变的当前行为

https://1drv.ms/u/s!AtCaUNAJbbvIhupxuJSHh3kSkBNTxw?e=KAtshL

powershell powershell-core tab-completion powershell-7.3 validateset
1个回答
1
投票
  • 您上一个问题的已接受答案,需要分析参数完成脚本块内的命令 AST,以说明到目前为止键入/制表符完成的数组元素。

  • 实现期望的行为:

    • [ValidateSet()]
      属性可以 not 使用,因为它们抢占
      [ArgumentCompleter()]
      属性并且始终提供 all 有效值,无论哪些已经被指定为手头数组参数的一部分。

    • 相反,实现所需的排除已经指定的逻辑的

      [ArgumentCompleter()]
      属性必须与强制仅指定有效值的
      [ValidateScript()]
      属性相辅相成(假设用户可能手动输入了无效值) .


以下是一个简化的、自包含的示例,它使用硬编码的策略 ID 和名称,并定义函数

Foo
具有 2 个(位置)参数,可根据需要完成制表符。

  • 注:

    • 为简单起见,不考虑用户在尝试对给定数组元素进行制表符补全之前手动键入的内容;这样做需要更多的工作。

    • AST 分析简单地提取 all 到目前为止作为参数提供的字符串常量,跨所有参数,但至少在手头的情况下这不是问题,因为:

      • 两个参数的有效值不同。
      • 使用
        Compare-Object
        将常量与参数适当的值进行匹配,并且只有那些不存在的才会作为候选提供。
# Argument tab auto-completion and ValidateSet for Policy names.
Class PolicyNamez : System.Management.Automation.IValidateSetValuesGenerator {
  [string[]] GetValidValues() {
    # Use *hard-coded values for this sample code.
    return [string[]] ("VerifiedAndReputableDesktopFlightSupplemental", "VerifiedAndReputableDesktopEvaluationFlightSupplemental", "WindowsE_Lockdown_Flight_Policy_Supplemental", "Microsoft Windows Driver Policy")
  }
}   
  
# Argument tab auto-completion and ValidateSet for Policy IDs.
Class PolicyIDz : System.Management.Automation.IValidateSetValuesGenerator {
  [string[]] GetValidValues() {
    # Use *hard-coded values for this sample code.
    return [string[]] ("1658656c-05ed-481f-bc5b-ebd8c091502d", "2698656d-05ea-481c-bc5b-ebd8c991802d", "5eaf656c-29ad-4a12-ab59-648917362e70", "d2bda972-cdf9-4364-ac5d-0b44497f6816")
  }
}

# Sample function.
function Foo {
  [CmdletBinding()]
  param(
    [ArgumentCompleter({
        param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
        $candidates = [PolicyIDz]::new().GetValidValues()
        $existing = $commandAst.FindAll({ 
            $args[0] -is [System.Management.Automation.Language.StringConstantExpressionAst]
          }, 
          $false
        ).Value  
        Compare-Object -PassThru $candidates $existing | Where-Object SideIndicator -eq '<='
      })]
    [ValidateScript({
        if ($_ -notin [PolicyIDz]::new().GetValidValues()) { throw "Invalid policy ID: $_" }
        $true
      })]
    [string[]]$PolicyIDs,

    [ArgumentCompleter({
        param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
        $candidates = [PolicyNamez]::new().GetValidValues()
        $existing = $commandAst.FindAll({ 
            $args[0] -is [System.Management.Automation.Language.StringConstantExpressionAst]
          }, 
          $false
        ).Value  
      (Compare-Object -PassThru $candidates $existing | Where-Object SideIndicator -eq '<=').
        ForEach({ if ($_ -match ' ') { "'{0}'" -f $_ } else { $_ } })
      })]
    [ValidateScript({
        if ($_ -notin [PolicyNamez]::new().GetValidValues()) { throw "Invalid policy name: $_" }
        $true
      })]
    [string[]]$PolicyNames
  )
}
© www.soinside.com 2019 - 2024. All rights reserved.