Powershell: Most validation parameter attribute types cause the AllowNull attribute to be ignored

Created on 10 Jul 2017  路  11Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

& { param([AllowNull()] $Foo) $null -eq $Foo } $null
& { param([AllowNull()] [ValidateScript({$true})] $Foo) $null -eq $Foo } $null
& { param([AllowNull()] [ValidateLength(0, 10)] $Foo) $null -eq $Foo } $null
& { param([AllowNull()] [ValidateRange(1,2)] $Foo) $null -eq $Foo } $null
& { param([AllowNull()] [ValidatePattern('.*')] $Foo) $null -eq $Foo } $null
& { param([AllowNull()] [ValidateSet(1,2)] $Foo) $null -eq $Foo } $null
& { param([AllowNull()] [ValidateDrive("c:")] $Foo) $null -eq $Foo } $null

Expected behavior

True
True
True
True
True
True
True

To clarify, I expected the following behavior, which I think is a useful combination of AllowNull and other validation attributes:

If [AllowNull()] is (also) present:

  • If $null is actually being passed, allow the value and ignore any other validation attributes.
  • Otherwise, evaluate any other validation attributes as usual.

Actual behavior

True
param [...]  : Cannot validate argument on parameter 'Foo'. The argument is null, empty, or an element of the argument. [...]
[...]
param[...]  : Cannot validate argument on parameter 'Foo'. The argument is null, empty, or an element of the argument. [...]
[...]
param[...]  : Cannot validate argument on parameter 'Foo'. The argument is null, empty, or an element of the argument. [...]
[...]
param[...]  : Cannot validate argument on parameter 'Foo'. The argument is null, empty, or an element of the argument. [...] 
[...]
param[...] : Cannot validate argument on parameter 'Foo'. The argument is null, empty, or an element of the argument. [...]
[...]
param[...] : Cannot validate argument on parameter 'Foo'. The argument is null.

The AllowNull attribute is effectively ignored in the presence of the validation attributes in the snippet; switching the attribute order makes no difference.

Note how the last error message, triggered by the ValidateDrive attribute, differs.

The following validation attributes _can_ be combined with AllowNull:

  • ValidateCount
  • AllowEmptyString
  • AllowEmptyCollection

Environment data

PowerShell Core v6.0.0-beta.3 on macOS 10.12.5
PowerShell Core v6.0.0-beta.3 on Ubuntu 16.04.1 LTS
PowerShell Core v6.0.0-beta.3 on Microsoft Windows 10 Pro (64-bit; v10.0.14393)
Windows PowerShell v5.1.15063.413 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Issue-Discussion WG-Engine

Most helpful comment

Yes, but only if $null is being passed; in other words:

If [AllowNull()] is (also) present:

  • If $null is actually being passed, allow the value and ignore any other validation attributes.
  • Otherwise, evaluate any other validation attributes as usual.

All 11 comments

The attributes are checked one after the other ("and" not "or"). So the Validate attributes would also allow null, but it's not. I believe the behavior is by design.

@iSazonov:

Passing $null to param([AllowNull()] [ValidateScript({$true})] $Foo) satisfies _both_ attributes, for instance, yet it fails as described.

By contrast, passing $null to param([AllowNull()] [ValidateCount(0,1)] $Foo) works.

To me it makes sense to allow these combinations, assuming the AllowNull attribute is explicitly specified.

Please clarify that we meant:

& { param( [ValidateScript({$true})] $Foo) $null -eq $Foo } $null

 param([ValidateScript({$true})] $Foo) $null -eq $Foo  : Cannot validate argument on parameter 'Foo'. The argument is null, empty, or an element of the ...

@iSazonov:

I'm not sure I understand.

Yes, you can get the same symptom by omitting the [AllowNull()] attribute.

In other words: using an attribute such as [ValidateScript()] implicitly disallows $null, which would otherwise be allowed by default (in the absence of [Parameter(Mandatory)]).

Again, the point is that I think it makes sense to allow this combination, if [AllowNull()] is explicitly specified.

@mklement0 Thanks for clarify! There is another side - we should have the same behavior for PowerShell scripts and C# codes.

@iSazonov:

Re C#: Do you mean when writing compiled cmdlets? Are there existing differences?

Sorry, no difference.

Do you want the behavior: if [AllowNull()] attribute is passed then stop processing next attributes?

Yes, but only if $null is being passed; in other words:

If [AllowNull()] is (also) present:

  • If $null is actually being passed, allow the value and ignore any other validation attributes.
  • Otherwise, evaluate any other validation attributes as usual.

Thanks for clarify! Please move the explanation in first post.

@iSazonov: Done.

Was this page helpful?
0 / 5 - 0 ratings