Does a validation script execute for $null parameters?

This topic contains 0 replies, has 1 voice, and was last updated by  Forums Archives 5 years, 10 months ago.

  • Author
    Posts
  • #5641

    by scottbass at 2013-03-07 21:09:49

    Hi,

    Save this test script as foo.ps1:

    [CmdletBinding()]
    param(
    [Alias("Fullname")]
    [Parameter(
    Position=0,
    Mandatory=$true,
    ValueFromPipeline=$true,
    ValueFromPipelineByPropertyName=$true
    )]
    [AllowNull()]
    < #
    [ValidateScript(
    {
    # Allow $null (via the pipeline), or Strings and System.IO.* objects
    if ($_ -eq $null) {Write-Warning "There are no files to process."; $true}
    $objectType=$_.GetType().Fullname
    switch -wildcard ($objectType) {
    "System.IO.*" {$true}
    "System.String" {$true}
    default {throw "Invalid -Path: $objectType is invalid."; $false}
    }
    }
    )]
    #>
    [Object[]]$Path
    )

    process
    {
    # Process the pipeline
    If ($Path -eq $null) {Write-Warning "There are no files to process.";return $null}
    Foreach ($file in $Path) {$file}
    }

    Test it. I found it best to test in a debugger session with breakpoints on if ($_ -eq $null)... and If ($Path -eq $null)...

    PS C:\Documents and Settings\sbass\My Documents\My Powershell Scripts> $null | .\foo.ps1
    WARNING: There are no files to process.
    PS C:\Documents and Settings\sbass\My Documents\My Powershell Scripts> (gci foo -ea "SilentlyContinue") | .\foo.ps1

    Verify that gci on a non-existant file returns $null:

    PS C:\Documents and Settings\sbass\My Documents\My Powershell Scripts> (gci foo -ea "SilentlyContinue") -eq $null
    True

    Now remove the comment block from the ValidationScript and re-test:

    PS C:\Documents and Settings\sbass\My Documents\My Powershell Scripts> $null | .\foo.ps1
    C:\Documents and Settings\sbass\My Documents\My Powershell Scripts\foo.ps1 : Cannot validate argument on parameter 'Path'. The argument is null, empty, or an element of the a
    rgument collection contains a null value. Supply a collection that does not contain any null values and then try the command again.
    At line:1 char:18
    + $null | .\foo.ps1 < <<<
    + CategoryInfo : InvalidData: (:) [foo.ps1], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,foo.ps1

    PS C:\Documents and Settings\sbass\My Documents\My Powershell Scripts> (gci foo -ea "SilentlyContinue") | .\foo.ps1
    PS C:\Documents and Settings\sbass\My Documents\My Powershell Scripts>

    This isn't a huge deal; I can get rid of the ValidationScript and code the checks in the main body of the program. It's just that I find the current behaviour weird and inconsistent, and I've invested time with the ValidationScript approach.

    Regards,
    Scott

    by DexterPOSH at 2013-03-08 22:23:51

    Hi Scott,

    When I read the about topic, it shows me below:
    AllowNull Validation Attribute

    The AllowNull attribute allows the value of a mandatory parameter
    to be null ($null).

    And your script perfectly allows that
    PS>.\foo.ps1 -path $null
    WARNING: There are no files to process.

    But when you are piping you are passing the object and not passing a value, I guess.

    Does this makes sense ?

    by scottbass at 2013-03-09 07:19:22

    Hi Dexter:

    Without a validation script: piping $null gets passed to $path, the process section executes, and I get the warning. Piping gci of a non-existent file does nothing. But the test shows that gci of a non-existent file -eq $null

    With a validation script: piping $null, the validation script fails, but the validation script should allow $null and return $true. Piping gci has the same results as above.

    When I have a breakpoint in the debugger, gci non-existent doesn't trigger the break.

    It seems inconsistent to me...

    by DexterPOSH at 2013-03-22 16:16:33

    Have you tried tracing for what is happening behind the scenes here ?
    I am not sure that will help but that is the only thing I can think of right now...that could be done

    by MasterOfTheHat at 2013-03-25 09:29:14

    The problem is that you aren't exiting the validation script after you issue the Write-Warning and write $true to the output. Because of the way you have the validate script written, it continues to try and process the rest of the validate even if the param is $null. Simple enough fix, though. Just add "return" to where you want the script to exit.
    if ($_ -eq $null) {
    Write-Warning "There are no files to process."
    return $true
    }

    $objectType=$_.GetType().Fullname
    switch -wildcard ($objectType) {
    "System.IO.*"
    {
    return $true
    }
    "System.String"
    {
    return $true
    }
    default
    {
    throw "Invalid -Path: $objectType is invalid."
    }
    }

    Also notice that I added return statements to your switch block and took out the "$false" on the default case. Take a look at the "ValidateScript Validation Attribute" section in about_Functions_Advanced_Parameters. You'll see that the validate script will generate an if the script returns false or if the script throws an exception.

You must be logged in to reply to this topic.