互斥的powershell参数

时间:2009-11-19 23:08:16

标签: powershell parameters optional-parameters

SCENARIO

  • 我正在使用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只有两个可选参数,只需手动进行错误检查。这就是我目前实施的方式。
  • 或者,我对不同方法的建议感兴趣。

3 个答案:

答案 0 :(得分:42)

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

修改

“about_Functions_Advanced_Parameters”中的“ParameterSetName Named Argument”部分也记录了这一点。这就是使用像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

答案 1 :(得分:8)

以下是使用从PowerShell Community Extensions中的cmdlet中获取的ParameterSetName的示例。顺便说一句,对于你可以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语句所做的那样。

答案 2 :(得分:0)

我来这里是有一个附加要求:可选的互斥参数。

这里的帖子帮助我找到了一半答案。因此,我想将完整的答案发布在这里,以防有人有相同的要求。

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

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