I noticed that PowerShell rejects null and empty values for a parameter declared as mandatory, even though I did not add the ValidateNotNullOrEmpty attribute. For example:
function Test {
param(
[Parameter(Mandatory = $true)]
[string[]] $a
)
$a
}
Calls such as Test '', Test @('', 'a'), Test $null, and Test ('a', $null) all fail with errors saying that the argument is null or an empty string. Calling Test without supplying the parameter also produces an error.
Does the Mandatory attribute implicitly apply ValidateNotNullOrEmpty? How do AllowNull and AllowEmptyString affect this behavior, especially for array parameters?
3 Answers
This behaves similarly to ValidateNotNullOrEmpty, but it is not the same attribute. Mandatory performs the check once, while the parameter is being bound. After the function starts, the variable can still be assigned null or an empty string:
function Test {
param([Parameter(Mandatory)] [string[]] $a)
$a = $null
}
Test -a value
That assignment succeeds. If you add [ValidateNotNullOrEmpty()] explicitly, validation is attached to the variable and the later assignment fails as well. For collections, the binding check also examines the individual elements, which explains why an array containing both valid and empty or null entries is rejected.
Mandatory parameters receive a built-in null and empty-string check during parameter binding unless you explicitly allow those values. Use [AllowNull()], [AllowEmptyString()], or [AllowEmptyCollection()] when appropriate. For example:
function Test {
param(
[Parameter(Mandatory)]
[AllowNull()]
[AllowEmptyString()]
[string[]] $a
)
$a
}
The Allow* attributes are specifically intended to modify the restrictions that come with mandatory parameter binding.
One subtle detail is that the restriction can apply when a parameter is mandatory in any parameter set, even if it is optional in the particular set selected for a call. In practice, an explicitly supplied null or empty value may still be rejected unless the parameter has the appropriate Allow* attribute. If blank values are valid for the function, it can also be clearer to make the parameter optional and handle them yourself with methods such as [string]::IsNullOrEmpty() or [string]::IsNullOrWhiteSpace().

That distinction between parameter binding and validation for the lifetime of the variable clears up the confusion. The interaction with arrays and parameter sets is especially useful to know.