Passing null to a mandatory parameter to a function

You should be able to use the [AllowEmptyString()] parameter attribute for [string] parameters and/or the [AllowNull()] parameter attribute for other types. I've added the [AllowEmptyString()] attribute to the function from your example:

Function Foo {
    Param
    (
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]  <#-- Add this #>
        [string] $Bar
    )

    Write-Host $Bar
}

Foo -Bar $null

For more info, check out the about_Functions_Advanced_Parameters help topic.

Be aware that PowerShell will coerce a $null value into an instance of some types during parameter binding for mandatory parameters, e.g., [string] $null becomes an empty string and [int] $null becomes 0. To get around that you have a few options:

  • Remove the parameter type constraint. You can check for $null in your code and then cast into the type you want.
  • Use System.Nullable (see the other answer for this). This will only work for value types.
  • Rethink the function design so that you don't have mandatory parameters that should allow null.

As mentioned in Rohn Edwards's answer, [AllowNull()] and/or [AllowEmptyString()] are part of the solution, but a few things need to be taken into account.

Even though the example given in the question is with a type string, the question on the title is how to pass null to a mandatory parameter, without a mention of type, so we need to expand the answer slightly.

First let us look at how PowerShell handles assigning $null to certain types:

PS C:\> [int] $null
0
PS C:\> [bool] $null
False
PS C:\> [wmi] $null
PS C:\>
PS C:\> [string] $null

PS C:\>

Analyzing the results:

  • Passing $null to an [int] returns an [int] object with value 0
  • Passing $null to a [bool] returns a [bool] object with value False
  • Passing $null to a [wmi] returns ... nothing. It does not create an object at all. This can be confirmed by doing ([wmi] $null).GetType(), which throws an error
  • Passing $null to a [string] returns a [string] object with value '' (empty string). This can be confirmed by doing ([string] $null).GetType() and ([string] $null).Length

So, if we have a function with a non-mandatory [int] parameter what value will it have if we don't pass that parameter? Let's check:

Function Foo {
    Param (
        [int] $Bar
    )
    Write-Host $Bar
}

Foo
> 0

Obviously if it was a [bool] the value with be False and if it was a [string] the value would be ''

So when we have a mandatory parameter of most standard types and we assign it $null, we are not getting $null, but rather the "default value" for that type.

Example:

Function Foo {
    Param (
        [Parameter(Mandatory = $true)][int] $Bar
    )
    Write-Host $Bar
}

Foo -Bar $null
> 0

Notice there is no [AllowNull()] at all there, yet it still returns a 0.

A [string] is slightly different, in the sense that it doesn't allow empty strings on a mandatory parameter, which is why the example in the question fails. [AllowNull()] doesn't fix it either, as an empty string is not the same as $null and so we need to use [AllowEmptyString()]. Anything else will fail.

So, where does [AllowNull()] come in play, and how to pass a "real" $null to an int, bool, wmi, etc?

Neither int nor bool are nullable types, so in order to pass a "real" $null to them you need to make them nullable:

Function Foo {
    Param (
        [Parameter(Mandatory = $true)][AllowNull()][System.Nullable[int]] $Bar
    )
    Write-Host $Bar
}

This allows a "true" $null to be passed to an int, obviously when calling Write-Host it converts the $null to a string meaning we end up with an '' again, so it will still output something, but it is a "true" $null being passed.

Nullable types like [wmi] (or a .NET class) are easier as they are already nullable from the start, so they don't need to be made nullable, but still require [AllowNull()].

As for making a [string] truly nullable, that one still eludes me, as trying to do:

[System.Nullable[string]]

Returns an error. Very likely because a system.string is nullable already, though PowerShell doesn't seem to see it that way.

EDIT

I just noticed that while

[bool] $null

gets coerced into False, doing...

Function Foo {
    Param (
        [bool] $Bar
    )
    $Bar
}

Foo -Bar $null

throws the following error:

Foo : Cannot process argument transformation on parameter 'Bar'. Cannot convert value "" to type "System.Boolean".

This is quite bizarre, even more so because using [switch] in the function above instead of [bool] works.

Tags:

Powershell