Search code examples
powershellparametersattributes

Why Does PowerShell Re-evaluate the Validation of a Parameter When Its Value Changes


I’m currently writing a simple PowerShell(5) script. It should take user input and then perform some tasks based on the input. I assign ValidateScript to the input parameter to validate user input. According to the PowerShell documentation, validation occurs before the code runs, so I’m changing the value of the user’s input. However, this is causing an error.

Consider following simple example.


  [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateScript({ $_ -gt 0 })]
        [int]$InputParameter
    )

    process {
       
        $InputParameter = -1

      
    }
} 

Running TEST-FUNCTION 0 Yields an error

TEST-FUNCTION : Cannot validate argument on parameter 'InputParameter'. The " $_ -gt 0 " validation script for the
argument with value "0" did not return a result of True. Determine why the validation script failed, and then try the
command again.
At line:1 char:15
+ TEST-FUNCTION 0
+               ~
    + CategoryInfo          : InvalidData: (:) [TEST-FUNCTION], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,TEST-FUNCTION

This makes sense, as it's not passing the initial validation.

However, running TEST-FUNCTION 1 also yields an error.

The variable cannot be validated because the value -1 is not a valid value for the InputParameter variable.
At line:12 char:9
+         $InputParameter = -1
+         ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ValidationMetadataException
    + FullyQualifiedErrorId : ValidateSetFailure

The two function calls give two different errors. I’m not sure why I can’t change the value of the parameter after it has passed validation. Is there any workaround that can prevent the second round of evaluation? Thanks!


Solution

  • Because the attribute gets attached to the PSVariable metadata, simple example no function needed:

    [ValidateScript({ $_ -gt 0 })]
    [int] $InputParameter = 1
    
    (Get-Variable InputParameter).Attributes |
        Where-Object TypeId -EQ ([System.Management.Automation.ValidateScriptAttribute])
    
    # ErrorMessage ScriptBlock TypeId
    # ------------ ----------- ------
    #               $_ -gt 0   System.Management.Automation.ValidateScriptAttribute
    

    Since .Attributes is a collection, you could remove it but really it's much easier to just use a different variable name in your function:

    $psvar = Get-Variable InputParameter
    $attributeToRemove = $psvar.Attributes |
        Where-Object TypeId -EQ ([System.Management.Automation.ValidateScriptAttribute])
    
    $InputParameter = -1
    # MetadataError: The variable cannot be validated because the value -1 is not a valid....
    
    $null = $psvar.Attributes.Remove($attributeToRemove)
    
    $InputParameter = -1 # OK