English 中文(简体)
Mutually exclusive powershell parameters
原标题:

SCENARIO

  • I m writing a cmdlet for Powershell 2.0 using Visual Studio 2008 and .NET 3.5
  • the cmdlet requires 3 arguments.

my intended grammar of the cmdlet is something like this:

cmdletname [foo|bar] p1, p2
  • That reads as the user must give a value for "-foo" or "-bar" but can t give both together.

EXAMPLE OF VALID INPUT

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

EXAMPLE OF INVALID INPUT

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

MY QUESTION

  • My question is on how to do this in powershell so that it does all the checking for me - or if that is possible at all.
  • I know I can use just have two optional parameters for foo and bar and simply do the error checking manually. That s how I have it implemented currently.
  • Alternatively, I am interested in suggestions for different approaches.
最佳回答

Here s an example of using ParameterSetName taken from a cmdlet in the PowerShell Community Extensions. BTW, for ideas you can 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;
            }
        });
    }
    ...
}

Note that the cmdlet typically declares a default ParameterSetName that helps PowerShell determine the "default" parameter set to use when there is ambiguity. Later on, if needed, you can determine which parameter set is in force by querying this.ParameterSetName as the switch statement does above in the EndProcessing() override.

问题回答

You can use the parameter attribute to declare multiple parameter sets. You then simply assign parameters that are mutually exclusive to different parameter sets.

EDIT:

This is also documented in about_Functions_Advanced_Parameters , under the section "ParameterSetName Named Argument". This is how different sets of parameters is handled with cmdlets like Get-Random (which has mutually exclusive parameters):

> 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

Here s an example of doing it in a function:

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

The parameters one and two are in different parameter sets, so they cannot be specified together:

> 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

Which is the same error I got with Get-Random. But I can use the parameters independently:

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

...or:

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

I came here but with an additional requirement: Optional mutual exclusive parameters.

This post here helped me to find half of the answer. So I thought to post here the full answer in case someone has the same requirements.

The code below can be used at the top of a Powershell script to have 4 optional parameters of which LaunchAsAdmin and LaunchAsCouponBrowser are mutually exclusive while token and WorkstationName are also optional but can be combined with any other parameter.

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




相关问题
Mutually exclusive powershell parameters

SCENARIO I m writing a cmdlet for Powershell 2.0 using Visual Studio 2008 and .NET 3.5 the cmdlet requires 3 arguments. my intended grammar of the cmdlet is something like this: cmdletname [foo|...

Run a program from PowerShell with timeout

I ll write a script that runs a program and wait for it finished. But if the program is not finished within a specified time I want that the program is killed.

How to transpose data in powershell

I have a file that looks like this: a,1 b,2 c,3 a,4 b,5 c,6 (...repeat 1,000s of lines) How can I transpose it into this? a,b,c 1,2,3 4,5,6 Thanks

Powershell v2 remoting and delegation

I have installed Powershell V2 on 2 machines and run Enable-PsRemoting on both of them. Both machines are Win 2003 R2 and are joined to the same active directory domain and I can successfully run ...

PowerShell -match operator and multiple groups

I have the following log entry that I am processing in PowerShell I m trying to extract all the activity names and durations using the -match operator but I am only getting one match group back. I m ...

热门标签