互斥的powershell参数

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

场景

  • 我正在使用 Visual Studio 2008 和 .NET 3.5 为 Powershell 2.0 编写一个 cmdlet
  • cmdlet 需要 3 个参数。

我想要的 cmdlet 语法是这样的:

cmdletname [foo|bar] p1, p2
  • 这意味着用户必须为“-foo”或“-bar”提供一个值,但不能同时提供两者。

有效输入示例

cmdletname -foo xxx -p1 hello  -p2 world
cmdletname -bar yyy -p1 hello  -p2 world

无效输入示例

cmdletname -foo xxx -bar yyy -p1 hello  -p2 world

我的问题

  • 我的问题是如何在 powershell 中执行此操作,以便它为我完成所有检查 - 或者是否可能。
  • 我知道我可以只使用 foo 和 bar 两个可选参数,然后手动进行错误检查。这就是我目前实施的方式。
  • 或者,我对不同方法的建议感兴趣。
powershell parameters optional-parameters
4个回答
61
投票

您可以使用参数属性来声明多个参数集。然后,您只需将互斥的参数分配给不同的参数集即可。

编辑:

这也记录在“about_Functions_Advanced_Parameters”中的“ParameterSetName 命名参数”部分下。这是使用

Get-Random
(具有互斥参数)等 cmdlet 处理不同参数集的方式:

> get-random -input 4 -max 77
Get-Random : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:11
+ get-random <<<<  -input 4 -max 77
    + CategoryInfo          : InvalidArgument: (:) [Get-Random], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.GetRandomCommand

这是在函数中执行此操作的示例:

function exclusive_params() { 
    param( 
        [parameter(ParameterSetName="seta")]$one,
        [parameter(ParameterSetName="setb")]$two, 
        $three 
    )
    "one: $one"; "two: $two"; "three: $three" 
}

参数

one
two
位于不同的参数集中,因此不能一起指定:

> exclusive_params -one foo -two bar -three third
exclusive_params : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:17
+ exclusive_params <<<<  -one foo -two bar -three third
    + CategoryInfo          : InvalidArgument: (:) [exclusive_params], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,exclusive_params

这与我使用 Get-Random 时遇到的错误相同。但我可以独立使用参数:

> exclusive_params -one foo -three third
one: foo
two:
three: third

...或:

> exclusive_params -two bar -three third
one:
two: bar
three: third

9
投票

以下是使用从 PowerShell 社区扩展中的 cmdlet 获取的 ParameterSetName 的示例。 顺便说一句,对于想法,您可以浏览 PSCX 源代码

[Cmdlet(VerbsCommon.Set, PscxNouns.Clipboard, 
        DefaultParameterSetName = ParamSetText)]
[Description("Copies the item in the system clipboard.")]
[RelatedLink(typeof(GetClipboardCommand))]
[RelatedLink(typeof(OutClipboardCommand))]
[RelatedLink(typeof(WriteClipboardCommand))]
public class SetClipboardCommand : ClipboardCommandBase
{
    ... fields elided

    const string ParamSetRtf = "Rtf";
    const string ParamSetHtml = "Html";
    const string ParamSetText = "Text";
    const string ParamSetFiles = "Files";
    const string ParamSetImage = "Image";
    . 
    [AllowNull]
    [Parameter(ValueFromPipeline = true, ParameterSetName = ParamSetImage)]
    public Image Image { get; set; }
    . 
    [AllowNull]
    [AllowEmptyCollection]
    [Parameter(ValueFromPipeline = true, ValueFromRemainingArguments = true,
               ParameterSetName = ParamSetFiles)]
    public FileSystemInfo[] Files { get; set; }
    . 
    [AllowNull]
    [AllowEmptyString]
    [Parameter(ValueFromPipeline = true, ValueFromRemainingArguments = true,
               ParameterSetName = ParamSetText)]
    public string Text { get; set; }
    . 
    [Parameter(ValueFromPipeline = true, ValueFromRemainingArguments = true,
               ParameterSetName = ParamSetHtml)]
    public string Html { get; set; }
    .         
    [Parameter(ValueFromPipeline = true, ValueFromRemainingArguments = true,
               ParameterSetName = ParamSetRtf)]
    public string Rtf { get; set; }
    . 
    protected override void ProcessRecord()
    {
        ...
    }
    .
    protected override void EndProcessing()
    {
        ExecuteWrite(delegate
        {
            switch (ParameterSetName)
            {
                case ParamSetFiles:
                    if (Paths.Count == 0)
                        WinFormsClipboard.Clear();
                    else
                        WinFormsClipboard.SetFileDropList(_paths);
                    break;

                case ParamSetImage:
                    if (Image == null)
                        WinFormsClipboard.Clear();
                    else
                        WinFormsClipboard.SetImage(_image);
                    break;

                case ParamSetRtf:
                    SetTextContents(Rtf, TextDataFormat.Rtf);
                    break;

                case ParamSetHtml:
                    SetTextContents(Html, TextDataFormat.Html);
                    break;

                default:
                    SetTextContents(Text, TextDataFormat.UnicodeText);
                    break;
            }
        });
    }
    ...
}

请注意,cmdlet 通常会声明一个默认的 ParameterSetName,以帮助 PowerShell 确定在存在歧义时要使用的“默认”参数集。 稍后,如果需要,您可以通过查询 this.ParameterSetName 来确定哪个参数集有效,就像上面 EndProcessing() 覆盖中的 switch 语句所做的那样。


8
投票

我来到这里,但有一个额外的要求:可选的互斥参数。

这篇文章帮助我找到了一半的答案。 所以我想在这里发布完整的答案,以防有人有相同的要求。

下面的代码可以在 Powershell 脚本的顶部使用,以具有 4 个可选参数,其中 LaunchAsAdmin 和 LaunchAsCouponBrowser 是互斥的,而 token 和 WorkstationName 也是可选的,但可以与任何其他参数组合。

[CmdletBinding(DefaultParametersetName="default")]                  
Param(
    [string]$token,
    [string]$WorkstationName,
    [parameter(ParameterSetName="seta")][switch]$LaunchAsAdmin,
    [parameter(ParameterSetName="setb")][switch]$LaunchAsCouponBrowser  
)

0
投票

Parameter 属性的一个缺点是,如果您有 n 组互斥的参数,则似乎需要 2^n 个参数组。 如果 n 可能是 3 或更少,那还好,但如果 n 是 4 或更大,那就太难了。

© www.soinside.com 2019 - 2024. All rights reserved.