Defining parameters - which method is better, and why?

This topic contains 0 replies, has 1 voice, and was last updated by Profile photo of Forums Archives Forums Archives 5 years, 3 months ago.

  • Author
    Posts
  • #5085

    by Pat Richard at 2012-09-08 06:51:18

    Which method is better when defining parameters in a param block?
    [Parameter(Mandatory = $True, HelpMessage = "You forgot something!")]
    or
    [ValidateNotNullOrEmpty()]

    by DonJ at 2012-09-08 07:49:11

    Well, those two things each do something different. To provide the more full-form definition for later readers:


    [CmdletBinding()]
    Param(
    [Parameter(Mandatory=$True,HelpMessage="Computer name")][ValidateNotNullOrEmpty()][string]$computername
    )

    or


    [CmdletBinding()]
    Param(
    [Parameter(Mandatory=$True,HelpMessage="Computer name")]
    [ValidateNotNullOrEmpty()]
    [string]$computername
    )

    (I like the latter version better).

    If you're asking, "which is the preferred way to ensure a parameter isn't left empty," it depends on what you mean by "empty." In PowerShell, "empty" means "lacking a value;" but you can fill a parameter with $null and it won't be empty ($null is considered a value). ValidateNotNullOrEmpty will throw an error if the parameter is either empty or contains only $null. Mandatory will prompt if the parameter is empty. So "which is better" depends a bit on what you want it to do.

    With Mandatory, you get a shell-standard prompt for a missing parameter, but passing in a value of $null will satisfy it. ValidateNotNullOrEmpty will never prompt, will only throw an error, and will disallow $null.

    I tend to prefer Mandatory, mainly because it gives someone a change to fill-in the needed information from the shell's prompt (and I don't have to code that prompt, which is nice). But I sometimes ALSO use ValidateNotNullOrEmpty, if I need to ensure that the values I got are non-null.

    by willsteele at 2012-09-08 10:39:19

    I have always found the second version listed above, where each attribute is broken out per line, because I can see, at a glance, exactly what is contained in each parameter. Otherwise, I find myself having to read through a long set of strings with varying formats, standards and patterns. Also, I tend to place a blank line between each [Parameter()] attribute collection. That way I can quickly glance at a large list of parameters and pick through the specifics with much less work. Granted, these lead to much longer scripts, if you are doing big, well-handled parameter attribute sets. However, if you are at the point of making sure it is as robust as possible I suspect the length of the param() section is arbitrary. It is for me anyway.

    On a side note, I tend to avoid the pattern where you place the parameters in the function line in parentheses. It can get really ugly for larger functions. If I have to do something in a pinch I might do it that way, but, I can probably count on two hands the number of times I have liked the way that worked for me.

    by DonJ at 2012-09-08 10:47:26

    [quote]On a side note, I tend to avoid the pattern where you place the parameters in the function line in parentheses. It can get really ugly for larger functions. If I have to do something in a pinch I might do it that way, but, I can probably count on two hands the number of times I have liked the way that worked for me.[/quote]

    As an aside, PowerShell internally stores functions with a Param() block, regardless of how you define them.

    by Pat Richard at 2012-09-08 18:34:41

    Thanks, Don. The second method you show is what I typically use, but started to think that setting mandatory AND using NotNullOrEmpty was redundant, and therefore, not needed.

    by poshoholic at 2012-09-08 21:45:42

    You are correct that there is a redundancy when you use Mandatory and ValidateNotNullOrEmpty for a parameter. Mandatory implicitly indicates that the parameter is required and that it cannot be null or empty. Personally I always put both of them even if there is a redundancy though, since it is easier to see the intended behaviour this way when reviewing the function.

    by DonJ at 2012-09-09 07:41:46

    Kirk, I've got an instance in front of me where Mandatory accepts an explicit $null.

    by poshoholic at 2012-09-09 21:06:09

    Are you sure? Look at the following transcript:

    PS C:\> function Test-Mandatory {
    >> [CmdletBinding()]
    >> param(
    >> [Parameter(Mandatory=$true)]
    >> [String]
    >> $Value
    >> )
    >> $Value
    >> }
    >>
    PS C:\> Test-Mandatory -Value $null # Try passing in $null directly; fails as expected
    test-mandatory : Cannot bind argument to parameter 'Value' because it is an empty string.
    At line:1 char:23
    + Test-Mandatory -Value $null
    + ~~~~~
    + CategoryInfo : InvalidData: (:) [test-mandatory], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,test-mandatory

    PS C:\> Test-Mandatory -Value '' # Try passing in an empty string; this also fails as expected.
    test-mandatory : Cannot bind argument to parameter 'Value' because it is an empty string.
    At line:1 char:23
    + Test-Mandatory -Value ''
    + ~~
    + CategoryInfo : InvalidData: (:) [test-mandatory], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,test-mandatory

    PS C:\> Test-Mandatory $null # Do the same without a parameter name; still fails as expected
    test-mandatory : Cannot bind argument to parameter 'Value' because it is an empty string.
    At line:1 char:16
    + Test-Mandatory $null
    + ~~~~~
    + CategoryInfo : InvalidData: (:) [test-mandatory], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,test-mandatory

    PS C:\> Test-Mandatory '' # And with an empty string; another failure
    test-mandatory : Cannot bind argument to parameter 'Value' because it is an empty string.
    At line:1 char:16
    + Test-Mandatory ''
    + ~~
    + CategoryInfo : InvalidData: (:) [test-mandatory], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,test-mandatory

    PS C:\> Test-Mandatory # What if we don't pass any parameters, and then enter $null?

    cmdlet test-mandatory at command pipeline position 1
    Supply values for the following parameters:
    Value: $null
    $null

    # That looks like it "worked", but it didn't really accept null. It took our value of $null as a literal string, as if we had passed in '$null', which is not null or empty.
    PS C:\> Test-Mandatory # Now do it again with an empty string

    cmdlet test-mandatory at command pipeline position 1
    Supply values for the following parameters:
    Value: ''
    # Again, it seems like it "worked", but it took our quotes as a literal string containing two single quotes, which is not null or empty.
    PS C:\> Test-Mandatory # Now let's do it and just press enter for the mandatory parameter; this fails as expected

    cmdlet test-mandatory at command pipeline position 1
    Supply values for the following parameters:
    Value:
    test-mandatory : Cannot bind argument to parameter 'Value' because it is an empty string.
    At line:1 char:1
    + Test-Mandatory
    + ~~~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [test-mandatory], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,test-mandatory

    ''

    This is the case even if I try to force it to accept null using the AllowNull attribute for the parameter. How are you passing in $null to a mandatory parameter and having it accepted?

You must be logged in to reply to this topic.