【问题标题】:Mutually exclusive powershell parameters互斥powershell参数
【发布时间】:2009-11-19 23:08:15
【问题描述】:

场景

  • 我正在使用 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


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 上述建议中没有强调的是,除了将互斥参数移动到令牌和工作站参数下方之外,您还需要添加 CmdletBinding 引用。否则,当执行不带参数的函数时,Powershell 会给你一个可怕的“AmbiguousParameterSet”错误。如果您对 CmdletBinding 行不感兴趣,Powershell 将期望所有参数都是“强制”的。
    【解决方案2】:

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

    编辑:

    这也记录在“参数集名称命名参数”部分的“about_Functions_Advanced_Parameters”中。这就是使用 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" 
    }
    

    参数onetwo在不同的参数集中,不能一起指定:

    > 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
    

    【讨论】:

    • 非常好,准确回答了我的问题,我不知道为什么没有更多的投票!
    【解决方案3】:

    这是一个使用 ParameterSetName 的示例,该示例取自 PowerShell Community Extensions 中的 cmdlet。顺便说一句,您可以browse the PSCX source code获得想法。

    [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 语句所做的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-29
      • 2017-01-03
      • 2014-03-10
      • 2013-07-07
      • 2020-07-14
      • 2011-01-06
      • 1970-01-01
      相关资源
      最近更新 更多