Search code examples
powershellvalidationparameterscasting

Function parameter validation in Powershell


Why does a [string] casted parameter with the 'value' $null in this example never throw an error (empty or $null), but a string with the value '$null' always throws? I would expect if passing a mandatory parameter, it is checked for $null/emptyness and thus an error is always thrown in these cases:

Function test_M_NoE ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $x ) {}

# test cases. Uncomment one:
[string]$x = [string]$null 
# $x = [string]$null
# [string]$x = $null
# $x = $null 

"1:"; test_M_NoE [string]$x # never error
"2:"; test_M_NoE $x         # always error

Solution

  • The reason this works:

    test_M_NoE [string]$x
    

    Is that [string]$x is not being interpreted the way you expect.

    Let's change your test function definition to help us better see what's actually going on:

    function test_M_NoE {
      param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$x
      )
    
      Write-Host "Argument value passed was: '$x'"
    }
    

    Now, let's try again:

    PS ~> $x = $null
    PS ~> test_M_NoE [string]$x
    Argument value passed was: '[string]'
    

    Aha! The argument expression [string]$x did not result in an empty string - it resulted in the literal string value [string].

    This is due to the fact that PowerShell attempts to parse command arguments differently from anything else. From the about_Parsing help topic:

    Argument mode is designed for parsing arguments and parameters for commands in a shell environment. All input is treated as an expandable string unless it uses one of the following syntaxes: [...]

    So really, PowerShell interprets our argument expression like a double-quoted string:

    test_M_NoE "[string]$x"
    

    At which point the behavior makes sense - $x is $null, so it evaluates to an empty string, and the result of the expression "[string]$x" is therefore just [string].

    Enclose the argument expression in the $(...) subexpression operator to have it evaluated as a value expression instead of as an expandable string:

    test_M_NoE $([string]$x)