在 PowerShell 脚本中定义动态 ValidateSet 的正确方法是什么?

Jas*_*son 9 powershell

我有一个 PowerShell 7.1 帮助程序脚本,用于将项目从 subversion 复制到本地设备。我希望通过启用 PowerShell 将参数自动补全到此脚本中来使此脚本更易于使用。经过一些研究,看起来我可以实现一个接口来通过 ValidateSet 提供有效参数。

\n

根据微软的文档,我尝试这样做:

\n
[CmdletBinding()]\nparam (\n    [Parameter(Mandatory)]\n    [ValidateSet([ProjectNames])]\n    [String]\n    $ProjectName,\n\n    #Other params\n)\n\nClass ProjectNames : System.Management.Automation.IValidateSetValuesGenerator {\n    [string[]] GetValidValues() {\n        # logic to return projects here.\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

当我运行它时,它不会自动完成,并且出现以下错误:

\n
\xe2\x9d\xaf Copy-ProjectFromSubversion.ps1 my-project\nInvalidOperation: C:\\OneDrive\\Powershell-Scripts\\Copy-ProjectFromSubversion.ps1:4\nLine |\n   4 |      [ValidateSet([ProjectNames])]\n     |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n     | Unable to find type [ProjectNames].\n
Run Code Online (Sandbox Code Playgroud)\n

这是有道理的,因为类在参数之后才被定义。所以我将类移到了参数上方。显然这是一个语法错误。那么我该怎么做呢?在简单的 PowerShell 脚本中不可能吗?

\n

mkl*_*nt0 13

事实上,您遇到了第 22 条军规:要使参数声明在脚本解析阶段起作用,[ProjectNames]必须已经定义类,但不允许将类定义放在参数声明之前。

使用独立脚本文件 ( )最接近您的意图.ps1是使用该ValidateScript属性:

[CmdletBinding()]
param (
  [Parameter(Mandatory)]
  [ValidateScript(
    { $_ -in (Get-ChildItem -Directory).Name },
    ErrorMessage = 'Please specify the name of a subdirectory in the current directory.'
  )]
  [String] $ProjectName # ...
)
Run Code Online (Sandbox Code Playgroud)

限制

  • [ValidateScript]没有也不能提供制表符补全脚本块, { ... },提供的验证仅期望返回Boolean,并且不能保证甚至涉及一组离散值。

  • 同样,您无法在属性值中引用动态生成的有效值集(在脚本块内生成)ErrorMessage

解决这些限制的唯一方法是复制计算有效值的脚本块部分,但这可能会成为维护难题

要获得制表符完成功能,您必须在[ArgumentCompleter]属性中复制代码的相关部分:

[CmdletBinding()]
param (
  [Parameter(Mandatory)]
  [ValidateScript(
    { $_ -in (Get-ChildItem -Directory).Name },
    ErrorMessage = 'Please specify the name of a subdirectory in the current directory.'
  )]
  [ArgumentCompleter(
    {
      param($cmd, $param, $wordToComplete)
      # This is the duplicated part of the code in the [ValidateScipt] attribute.
      [array] $validValues = (Get-ChildItem -Directory).Name
      $validValues -like "$wordToComplete*"
    }
  )]
  [String] $ProjectName # ...
)
Run Code Online (Sandbox Code Playgroud)