2

问题:希望更改显示的错误消息以说明他们需要将“-passed”、“-warning”或“-failed”包含在 cmdlet 参数中,或者不关心这三个参数是否丢失并编写消息(假设它那里)。

说明:创建了一个接受三个参数的函数:一条消息、第二条消息和消息状态(通过、失败、警告)。我收到“无法使用指定的命名参数解析参数”的默认错误消息。无论您是否通过以下方式传递消息,都会发生这种情况:

PS C:\> Write-Message;
Write-Message : Parameter set cannot be resolved using the specified named parameters.
...
//or
PS C:\> Write-Message -Message "Hello World";

但是,如果您要输入“状态”参数,它将毫无问题地工作:

PS C:\> Write-Message -Message "Hello World" -Passed;
Hello World 

('Hello World' 应该是这里的绿色,但 Stack Overflow 还没有这个功能)

有问题的功能:

Function Write-Message {
    param(
        [string]$Message,
        [string]$MessageTwo,
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName = $true, ParameterSetName ="Passed")][switch]$Passed,
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName = $true, ParameterSetName ="Warning")][switch]$Warning,
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName = $true, ParameterSetName ="Failed")][switch]$Failed
    );
    $NewLineNeeded = [string]::IsNullOrEmpty($MessageTwo);

    if ($Passed){
        $color = 'green';
    }
    if($Warning){
        $color = 'yellow';
    }
    if($Failed){
        $color = 'red';
    }

    if($Passed -or $Warning -or $Failed){
        if(!$NewLineNeeded){
            Write-Host $MessageOne -NoNewline;
            Write-Host $MessageTwo -ForegroundColor $color;
        } else {
            Write-Host $Message -ForegroundColor $color;
        }  
    }
}
4

2 回答 2

3

为了补充Bender the Greatest 的有效解决方案和有用的解释,提供更多背景信息

[Parameter()]未通过其属性标记为属于至少一个参数集的参数:

  • 隐含地认为是所有已定义参数集的一部分。

  • 被分配了自动__AllParameterSets参数集。

Write-Message您可以使用您的函数进行如下验证:

(Get-Command Write-Message).Parameters.GetEnumerator() | 
  Select-Object @{ n='ParameterName'; e = { $_.Key } },
    @{ n='ParameterSets'; e = { $_.Value.ParameterSets.GetEnumerator().ForEach('Key') } }

上面的产量(省略了常用参数):

ParameterName       ParameterSets
-------------       -------------
Message             __AllParameterSets
MessageTwo          __AllParameterSets
Passed              Passed
Warning             Warning
Failed              Failed
# ...

重要提示:一旦将参数标记为属于参数集,它属于此参数集,如果它还需要属于其他参数集,则需要多个单独[Parameter(ParameterSetName = '...')]的属性 - 每个感兴趣的参数集一个。

当使用给定的一组参数值调用给定的函数或脚本时,PowerShell 会尝试明确推断要应用的参数集,并在$PSCmdlet.ParameterSetName.

如果不能明确推断出单个参数集,则会发生语句终止错误;也就是说,函数的调用根本上会失败(但默认情况下会继续执行脚本)。这可能是由于以下两个原因之一:

  • 传递了互斥参数:指定了属于不同参数集的参数(没有至少一个共同的关联参数集的参数)。

  • 传递了一个模棱两可的参数组合:不清楚要选择哪个参数集,因为可以应用多个参数。

两种情况下的错误消息是相同的:

Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.

顺便说一句:如果您仅指定参数名称的前缀(PowerShell 通常支持),并且该前缀不明确,即它匹配多个参数,则可能会出现额外的错误;例如,-Out是模棱两可的,因为它同时匹配-OutVariable-OutBuffer

Parameter cannot be processed because the parameter name 'Out' is ambiguous. Possible matches include: -OutVariable -OutBuffer.

如果指定参数或仅指定未明确标记为属于参数集的参数,并且未定义默认参数集,PowerShell 将选择该__AllParameterSets集并将其反映在$PSCmdlet.ParameterSetName.
然而,令人惊讶的是,这只适用于只有一个明确定义的参数集。

使用两个或多个显式参数集(如您的情况),PowerShell 认为这种情况不明确并报告错误。

此GitHub 问题中讨论了这种令人惊讶的行为。

解决方法,如Bender 的回答所示,是通过放置在块上方的属性定义默认参数集;例如:[CmdletBinding()]param(...)[CmdletBinding(DefaultParameterSetName='Default')]

该参数集是隐式创建的,其名称可以自由选择;没有实际参数被标记为属于它。

现在,当您不指定参数或仅指定没有显式参数集标记的参数时,调用成功,并$PSCmdlet.ParameterSetName反映默认参数集的名称。

于 2019-11-21T13:32:02.847 回答
3

添加“默认”参数集来解决此问题。您实际上不必在代码中使用参数集,因此即使使用“默认”之类的参数也无需对代码进行额外更改即可工作。在编写更复杂的 cmdlet 时,我自己也遇到过这种情况,我将参数集用于互斥参数,但有些参数与参数集无关。

Function Write-Message {
  [CmdletBinding(DefaultParameterSetName="Default")]
  Param(
...

当您仅使用没有参数集的参数时,Powershell 似乎对正在使用哪个参数集感到困惑,并且您还在 cmdlet 中定义了参数集。

您只需要在满足以下所有条件的情况下执行此操作:

  • 已明确定义了两个或更多参数集
  • 尚未将现有参数集之一绑定为默认值
  • 拥有(并调用您的例程)未绑定到任一集合的参数

正如mklement0 的回答中所解释的那样,以及一些关于发生的事情的幕后信息,这可能是某种错误,这个解决方案是解决方法。

于 2019-11-12T16:05:21.907 回答