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 value0
- Passing
$null
to a[bool]
returns a[bool]
object with valueFalse
- 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.