In a Google+ discussion this week, Edi Prinz demonstrated an effect of the ValidationRange parameter attribute that surprised many of us. When you validate a parameter value, the validation rules are enforced on the parameter variable — and that enforcement persists on the variable for the entire function scope.
For example, this function has a Value parameter. It uses the ValidateRange parameter attribute to allow only parameter values between 3 and 8, inclusive.
function Test-Validation { Param ( [ValidateRange(3,8)] [Int32] $Value ) $Value = 3 * $Value $Value } |
Let’s call the function with a value of 4 (between 3 and 8) for the parameter.
Test-Validation –Value 4
The variable cannot be validated because the value
12 is not a valid value for the Value variable.
At C:\ps-test\Test-ParameterValidation.ps1:7 char:5
+ $Value = 3 * $Value
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ValidationMetadataException
+ FullyQualifiedErrorId : ValidateSetFailure
4
What’s happening here? Why is there an error when the Value parameter has a value of 4?
When you call the Test-Validation function with a value of 2 for the Value parameter, it returns a parameter validation error (“Cannot validate argument on parameter…”), as expected, because a parameter value of 2 is not between 3 and 8 inclusive.
PS C:\ps-test> Test-Validation -Value 2
Test-Validation : Cannot validate argument on parameter 'Value'.
The 2 argument is less than the minimum allowed range of 3.
Supply an argument that is greater than or equal to 3 and then try the command again.
At line:1 char:24
+ Test-Validation -Value 2
+ ~
+ CategoryInfo : InvalidData: (:) [Test-Validation],
ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Test-Validation
When you enter a parameter value that’s within the allowed range (such as 4), you don’t get a parameter validation error. Instead, the command that saves the product of “3 * $Value” (12) in the $Value variable causes a variable validation error (“…variable cannot be validated…”) error because 12 is not between 3 and 8 inclusive.
$Value = 3 * $Value |
The variable value failed the range test, even though the parameter value satisfied it. Notice that the final $Value command returns a value of 4, because the command to assign a value of 12 failed.
PS C:\ps-test> Test-Validation -Value 4
The variable cannot be validated because the
value 12 is not a valid value for the Value variable.
At C:\ps-test\Test-Validation.ps1:11 char:2
+ $Value = 3 * $Value
+ ~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ValidationMetadataException
+ FullyQualifiedErrorId : ValidateSetFailure
4
Surprisingly, the validation that we set on the Value parameter is enforced on the $Value variable, even though we didn’t set any validation on the variable.
Let’s see why it happens, when it happens, and how to fix it.
Why: Parameters and parameter variables
Why does this happen?
In Windows PowerShell, function parameters are automatically converted to variables so you can use them in function commands. For example, the -Value parameter automatically becomes a $Value variable. If Windows PowerShell didn’t do this for you, you might need to save the parameter value in local variable explicitly.
function Get-Triple { Param ([Int32]$Value) #<-— This parameter... $Value = 3 * $Value #<—- becomes this variable. } |
But, in the Test-Validation function script block, we forgot about the parameter-ness of this parameter variable and just thought of it as a variable. And that’s fine. Most of the time. But not when you’re using parameter validation attributes.
Where: What’s the scope of this effect?
Windows PowerShell applies parameter validation to the parameter variable in the script.
- Affects all Validate* attributes, such as ValidateSet and ValidatePattern, but not other attributes, such as Allow.
- Occurs in Windows PowerShell 2.0 and later. (In the Google+ discussion, you’ll see mentions of 4.0 and 3.0 in the Google+ conversation, but it happens in 2.0, too.)
How to override the validation
Now that we know the effect, it’s easy to avoid an error.
- Create a new variable and use the new variable in the calculations.For example, in this function, we create a second variable called $NewValue.
function Test-Validation { Param ( [ValidateRange(3,8)] [Int32] $Value) $NewValue = 3 * $Value $NewValue } |
- Beginning in Windows PowerShell 3.0, you can use the Validation attributes on variables, so you can set a new validation range on the parameter variable (or any other variable).
When you use ValidateRange to set a range of 0 – 9999 for the $Value variable, this function now runs without error.
function Test-Validation { Param ( [ValidateRange(3,8)] [Int32] $Value) [ValidateRange(0, 9999)]$Value = 3 * $Value $Value } |
Test-Validation -Value 4 12
But, to fix the problem, you have to know that it exists.
Many thanks to Edi Prinz for pointing this out and for filing a Connect documentation bug against the about_Functions_Advanced_Parameters help topic. I voted up the bug. Hope you do, too.
June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.
![[Google+]](http://www.sapien.com/blog/wp-content/uploads/GooglePlus.gif)