PowerShell Scripting with [ValidateScript]

The last few days we’ve been looking at parameter validation attributes you might use in a script of function. Yesterday I wrote about [ValidateRange] and demonstrated how you might use it. That attribute works fine for any values that can be evaluated as numbers. But dates are a different story. I got a comment with a suggestion for validating dates and at first glance it appears to work. For a very small range it might, but here’s the code I was testing with.


Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a date",ValueFromPipeline=$True)]
[ValidateRange("1/1/2012","4/1/2012")]
$Date
)

Process {
write-host $date -ForegroundColor Green
}

I’m expecting date between 1/1/2012 and 4/1/2012. Anything else should throw an exception. Now watch what happens as I pipe some values to this:


PS S:\> "2/12/2012","5/1/2012","12/1/2011","13/2/2012" | .\Demo-ValidateRange-Da
te.ps1
2/12/2012
C:\scripts\Demo-ValidateRange-Date.ps1 : Cannot validate argument on parameter
'Date'. The 5/1/2012 argument is greater than the maximum allowed range of 4/1/
2012. Supply an argument that is less than 4/1/2012 and then try the command ag
ain.
At line:1 char:79
+ "2/12/2012","5/1/2012","12/1/2011","13/2/2012" | .\Demo-ValidateRange-Date.ps
1 <<<<
+ CategoryInfo : InvalidData: (5/1/2012:String) [Demo-ValidateRan
ge-Date.ps1], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Demo-ValidateRa
nge-Date.ps1

12/1/2011
13/2/2012

Values that are outside the range and even those that are bogus still are accepted. If I cast $date to [DateTime] which is what I would normally do, then nothing works at all. But that's fine because there is another attribute that is better suited to this task: [ValidateScript()].

To use this attribute we'll insert a scriptblock inside the parentheses. The scriptblock can be as complicated as you need it to be, but it must evaluate to either True or False. Use $_ to indicate the parameter value. So using my datetime example, I might use a validation script like this:


Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a date",ValueFromPipeline=$True)]
[ValidateScript( {
[datetime]$start="1/1/2012"
$end=Get-Date
($_ -ge $start) -AND ($_ -le $end)
}
)]
[datetime]$Date
)

Process {
write-host $date -ForegroundColor Green
}

With a validation script I have much more flexibility. Now look at the results:


PS S:\> "2/12/2012","5/1/2012","3/15/2012","12/1/2011","13/2/2012" | .\Demo-Vali
dateScript-Date.ps1 | clip
2/12/2012 12:00:00 AM
C:\scripts\Demo-ValidateScript-Date.ps1 : Cannot validate argument on parameter
'Date'. The "
[datetime]$start="1/1/2012"
$end=Get-Date
($_ -ge $start) -AND ($_ -le $end)
" validation script for the argument with value "5/1/2012 12:00:00 AM" did not
return true. Determine why the validation script failed and then try the comma
nd again.
At line:1 char:92
+ "2/12/2012","5/1/2012","3/15/2012","12/1/2011","13/2/2012" | .\Demo-ValidateS
cript-Date.ps1 <<<< | clip
+ CategoryInfo : InvalidData: (5/1/2012:String) [Demo-ValidateScr
ipt-Date.ps1], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Demo-ValidateSc
ript-Date.ps1

3/15/2012 12:00:00 AM
C:\scripts\Demo-ValidateScript-Date.ps1 : Cannot validate argument on parameter
'Date'. The "
[datetime]$start="1/1/2012"
$end=Get-Date
($_ -ge $start) -AND ($_ -le $end)
" validation script for the argument with value "12/1/2011 12:00:00 AM" did no
t return true. Determine why the validation script failed and then try the comm
and again.
At line:1 char:92
+ "2/12/2012","5/1/2012","3/15/2012","12/1/2011","13/2/2012" | .\Demo-ValidateS
cript-Date.ps1 <<<< | clip
+ CategoryInfo : InvalidData: (12/1/2011:String) [Demo-ValidateSc
ript-Date.ps1], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Demo-ValidateSc
ript-Date.ps1

C:\scripts\Demo-ValidateScript-Date.ps1 : The input object cannot be bound to a
ny parameters for the command either because the command does not take pipeline
input or the input and its properties do not match any of the parameters that
take pipeline input.
At line:1 char:92
+ "2/12/2012","5/1/2012","3/15/2012","12/1/2011","13/2/2012" | .\Demo-ValidateS
cript-Date.ps1 <<<<
+ CategoryInfo : InvalidArgument: (13/2/2012:String) [Demo-Valida
teScript-Date.ps1], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Demo-ValidateScript-Date.ps1

The valid dates pass, dates outside the range fail the validation test and the last value which isn't a legal date also fails but with a slightly different error message. As with all of the validation attributes I could have inserted this code into the body of my script and thrown my own errors. That choice is up to you. [ValidateScript()] isn't difficult to use. Just remember to insert your commands into a scriptblock, use $_ for the parameter value, and make sure the scriptblock writes either $True or $False.

2 thoughts on “PowerShell Scripting with [ValidateScript]”

  1. hi,

    for fun, you can also use a function like:


    function istrue($isdate) {
    $isdate -is [datetime]
    }

    function test {
    Param (
    [Parameter(valuefrompipeline=$true)]
    [ValidateScript({ istrue $_ })]
    $date)
    Write-Output $date
    }


    PS> Get-Date | test

Comments are closed.