6

In PowerShell 1.0, if I have a cmdlet parameter of an enum type, what is the recommended method for testing whether the user specified that parameter on the cmdlet command line? For example:

MyEnum : int { No = 0, Yes = 1, MaybeSo = 2 }

class DoSomethingCommand : PSCmdlet
...
private MyEnum isEnabled;

[Parameter(Mandatory = false)]
public MyEnum IsEnabled
{
    get { return isEnabled; }
    set { isEnabled = value; }
}

protected override void ProcessRecord()
{
    // How do I know if the user passed -IsEnabled <value> to the cmdlet?
}

Is there any way to do this without having to seed isEnabled with a dummy value? By default it will equal 0, and I don't want to have to seed every parameter or add a dummy value to my enum. I've potentially got many cmdlets with 100's of parameters, there's got to be a better way. This is related to this question but I was looking for a cleaner way of doing this. Thanks.

5
  • @Jack Straw If you have "potentially got many cmdlets with 100's of parameters", you might want to look at breaking some of that functionality up. One of the key benefits of PowerShell is discoverability and having large numbers of parameters makes self discovery that much more difficult. Commented Jul 30, 2009 at 15:23
  • @Steven, sorry I may have been misleading - it's not each cmdlet that has 100's of params :), but many cmdlets which result in many parameters. Thank you for your comment. Commented Jul 30, 2009 at 18:08
  • 1
    How to determine if a parameter is passed to a Powershell Cmdlet Commented Mar 16, 2018 at 4:50
  • 1
    @RezaAghaei It is best to also include the point that you're making in your comment in case you delete your blog post later. In this case, that the code$PSBoundParameters.ContainsKey("paramater name") can be used to check if the parameter was specified. Commented Dec 27, 2018 at 3:38
  • @DaveF I see another answer is pointing to the same solution in short. Anyway, I added a summary of the blog post here as an answer, including the example. Commented Dec 27, 2018 at 3:57

6 Answers 6

11

In this case, I would use a nullable wrapper around the enum type e.g.

[Parameter(Mandatory = false)]
public MyEnum? IsEnabled { get; set; }

Note the ? modifier on MyEnum. Then you can test if it is set like so:

if (this.IsEnabled.HasValue) { ... }
Sign up to request clarification or add additional context in comments.

1 Comment

That's exactly what I was looking for. Thanks. I actually made the local variable, not the property the nullable type, which also works.
4

PowerShell aside, it's never good style to use 0 in that way. You should always use 0 for the most appropriate default. In this case, the most appropriate default should be something like "Unset."

Ultimately, this is nothing to do with PowerShell and everything to do with good coding practices for .NET.

  • Oisin

3 Comments

@x0n: Thank you for your response. Whether using 0 or not for enum values is an arguable point, but either way my existing product does have many 0 values for enums. I guess my broader question is, is this the pattern cmdlet developers use in this situation? Use a default, 'unspecified' value for each parameter, and test against that before applying the parameter values to the object in ProcessRecord()? This could get a bit unwieldy for large products with many parameter types.
In v2.0 of powershell, a new property was added: this.MyInvocation.BoundParameters where "this" is PSCmdlet. This is a hashtable of key/value pairs of the parameter names and values that were bound to the cmdlet. If your enum was specified, it will be in this dictionary. If it defaulted, it won't be there. I'm not aware of anything other than string hacking that will do the same in v1.0
x0n, thanks, I saw that 2.0 property. Unfortunately I need to code against 1.0 for now. I think Keith's answer below, using a nullable wrapper, is exactly what I am looking for.
4

As an option you can use $PSBoundParameters collection to check whether passed to the method.

Let’s suppose we have a json file like following { "p1": "value1", "p2": "value2" } and we want to create a function which accepts parameter p1 and p2 and update value of p1 and p2 in the file, if they are passed to the function. Let's say those values can be null and and having those values as null is not equivalent to not passing them.

For example Update-Values -p1 $null should update p1 to null and should not change p2.

To do so, we should be able to detect if the parameter has been passed to the method or not.

Example - How to detect if a parameter is passed, for an optional parameter which can accept null as value?

Function Update-Values ($p1, $p2) {
    If($PSBoundParameters.ContainsKey("p1")) {
        Write-Host "p1 passed"
    }
    else {
        Write-Host "p1 not passed"
    }
    If($PSBoundParameters.ContainsKey("p2")) {
        Write-Host "p2 passed"
    }
    else {
        Write-Host "p2 not passed"
    }
}

Then if you run the function using the following parameter:

Update-Values -p1 $null
# Update-Values -p1 "something"

As a result you will see:

p1 passed
p2 not passed

You can read the blog post here: How to determine if a parameter is passed to a Powershell Cmdlet.

2 Comments

This does not work when you are writing binary commands, the PSBoundParameters variable is not present in C#
@ShawnMelton feel free to suggest a better answer. - The sample code in the answer is obviously for PowerShell functions for those who reached to this page by search.
2

I know this thread is a little old now, but the best way to do this is to declare your parameter using the SwitchParameter type. Then your users don't have to pass -IsEnabled , they would just add something like -Enabled as a parameter.

You then test the .IsPresent property of your parameter to see if the caller added -Enabled to the call to the cmdlet.

1 Comment

@Darren: that definitely works for bool params, but I was looking for a solution for optional non-bool params. The nullable type seems to work well. Of course PS v2 now has a dictionary of params available in the cmdlet, so that's probably the way to go. Thanks.
1

Only thing I can see is to modify your enum so that value 0 is named Unknown or something like that.

Problem is that enums are just integers in background and integers are value types. Unfortunate consequence is that they need to have value and that value is 0 by default.

Comments

0
bool wasSpecified = MyInvocation.BoundParameters.ContainsKey("IsEnabled");

1 Comment

Note that this doesn't work correctly with Positional parameters. They are not found by Name in the BoundParameters, but are specified and have a value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.