Parameter validation

Validating parameters in a Powershell function

Parameter validation

Validating parameters in a Powershell function

Parameter validation

In this article we will talk about an option available in Powershell: the validation of parameters

The purpose of this option is, as the name suggests, to validate that a parameter passed to a function is indeed the one we expect.

Throughout this article we will keep the following script as a guideline.

function Do-SomeThing {
    [CmdletBinding()]
    param (
        [String[]]$ComputerName,
        [Int]$Age
    )

    begin {
        #The value of computername must not be null or empty
        if (($null -eq $ComputerName) -or ($ComputerName -eq "")) {
            throw "ComputerName cannot be empty or null"
        }
        #Test to verify that the computer name does not exceed 13 characters
        If ($ComputerName.Length -gt 13) {
            Throw "Computer name must not exceed 13 characters"
        }

        #Computer age must be between 5 and 10 years old
        if (!(($Age -gt 5) -and ($Age -lt 10))) {
            throw "the age must be between 5 and 10 years old"
        }

    }

    process {
    }

    end {
    }
}

[ValidateNotNullOrEmpty()] and [ValidateNotNull()]

ValidateNotNull : check only if the value passed to the parameter is a null value. It will still work if an empty string is passed.

ValidateNotNullOrEmpty : also checks if the value passed is null and if it is an empty string or collection.

In our example we can replace the following test

if (($null -eq $ComputerName) -or ($ComputerName -eq "")) {
    throw "ComputerName cannot be empty or null"
}

by simply modifying the declaration of our $ComputerName variable

Param (
    [ValidateNotNullOrEmpty()]
    [String[]]$ComputerName
)

[ValidateLength()]

This validation makes it possible to define a minimum and maximum size expected for a parameter.

In our example we want the ComputerName parameter to be at least 1 character and at most 13 characters.

We can therefore replace the test:

    If ($ComputerName.Length -gt 13) {
        Throw "Computer name must not exceed 13 characters"
    }

by the following parameter declaration:

Param (
    [ValidateLength(1,13)]
    [String[]]$ComputerName
)

But wait ! We had already modified the declaration of this parameter previously to add [ValidateNotNullOrEmpty ()]?

In fact, the validations of the parameters can be cumulated. In our case we declare the parameter this way:

    param (
        [ValidateNotNullOrEmpty()]
        [ValidateLength(1,13)]
        [String[]]$ComputerName
    )

ComputerName must not be null or empty and must be between 1 and 13 characters long.

[ValidateRange()]

It is sort of the counterpart to [ValidateLength ()] but for the numbers. As for [ValidateLength ()], it allows defining a minimum and maximum value that can take a parameter.

In our example, the age of the PC must be between 5 and 10 years. So we had the following test:

    if (!(($Age -gt 5) -and ($Age -lt 10))) {
        throw "the age must be between 5 and 10 years old"
    }

we can therefore replace this test by:

param (
    [ValidateRange(5,10)]
    [int]$Age
    )

[ValidateCount()]

As for ValidateRange() it allows to define the minimum number and the maximum number of object that can take a collection passed in parameter.

    param (
        [ValidateNotNullOrEmpty()]
        [ValidateLength(1,13)]
        [ValidateCount(1,3)]
        [String[]]$ComputerName
    )

In our example the ComputerName parameter must be neither null nor empty, must be between 1 and 13 characters and we can only pass 1 to 3 objects in the collection.

[ValidateSet()]

This validation provides a possible response list for the value of the parameter.

This validation can be made Case Sensitive, if at the end of the declaration, the ignoreecase value is set to $False

the following validation test

        #Make sure the value is one of the ones I want
        if("SEAT","AGENCY","STOCK" -notcontains $Site) {
            throw "The site must be SEAT, AGENCY or STOCK"
        }

maybe replace with the declaration of the following variable Site

    param (
        [ValidateSet("SEAT","AGENCY","STOCK",ignorecase=$true)]
        [String]$Site
    )

In our example, the parameter can only take one of the 3 defined values.

We also asked that the parameter value not be Case Sensitive therefore SEAT, Seat, seat are all correct values.

[ValidatePattern()]

Allows you to use a regular expression (REGEX) before testing the value of a parameter.

In our script, we had the following test

        #Test to find out if the ComputerName matches the company's nomenclature
        if ($ComputerName -notmatch "^SRV-\D{6}\d{3}$") {
            Throw "The ComputerName must be in the form SRV-LETTER(6)NUMBER(3)"
        }

We want to be sure that the ComputerName parameter is always in the form of a string starting with SRV- followed by 6 letters and 3 numbers.

We can replace this test with validation

    param (
        [ValidateNotNullOrEmpty()]
        [ValidateLength(1,13)]
        [ValidateCount(1,3)]
        [ValidatePattern('^SRV-\D{6}\d{3}$')]
        [String[]]$ComputerName
    )

[ValidateScript()]

This validation makes it possible to define a script which will be executed to validate the value of the parameter.

Our test to validate the existence of the path

        #Know if the path passed in parameter exists and is a directory
        IF (!(Test-Path $Path -PathType Container))
        {
            Throw "$($Path) is not a valid file"
        }

maybe replace with the following validation

    param (
        [ValidateScript(
            {IF (!(Test-Path -Path $_)) {
                Throw "$($Path) is not a valid file"
            } else {
                $true
            }
            }
        )]
        [String]$Path
    )

As you can imagine, the script may be something more complicated than a simple test like here.

Conclusion

To conclude we can simply compare our 2 versions of script.

The original script

function Do-SomeThing {
    [CmdletBinding()]
    param (
        [String[]]$ComputerName,
        [Int]$Age
    )

    begin {
        #The value of computername must not be null or empty
        if (($null -eq $ComputerName) -or ($ComputerName -eq "")) {
            throw "ComputerName cannot be empty or null"
        }
        #Test to verify that the computer name does not exceed 13 characters
        If ($ComputerName.Length -gt 13) {
            Throw "Computer name must not exceed 13 characters"
        }

        #Computer age must be between 5 and 10 years old
        if (!(($Age -gt 5) -and ($Age -lt 10))) {
            throw "the age must be between 5 and 10 years old"
        }

    }

    process {
    }

    end {
    }
}

Le scrpipt final

function Do-SomeThing {
    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [ValidateLength(1,13)]
        [ValidateCount(1,3)]
        [ValidatePattern('^SRV-\D{6}\d{3}$')]
        [String[]]$ComputerName,
        [ValidateScript({IF (!(Test-Path -Path $_)) {
            Throw "$($Path) is not a valid file"
        } else {
            $true
        }
        })]
        [String]$Path,
        [ValidateSet("SEAT","AGENCY","STOCK",ignorecase=$true)]
        [String]$Site,
        [ValidateRange(5,10)]
        [int]$Age
    )

    begin {
    }

    process {
    }

    end {
    }
}

We see quite clearly that we have reduced the lines of code necessary to validate the parameters and thus simplify the understanding of the script.


See also