fbpx

PowerShell ValidateSet Attribute: Best Input Validation 101

Input validation is crucial for reliable and error-free PowerShell scripts. In this article, we explore the power of PowerShell ValidateSet, enabling developers to define a restricted set of allowed values for function parameters. Join us as we dive into the world of ValidateSet, uncovering its capabilities for ensuring data integrity, enhancing script usability, and preventing erroneous inputs.

Including Input with a Parameter

To accept input using a parameter and restrict the available options using the ValidateSet attribute in PowerShell, you can define a parameter with the desired attribute. Here’s an example:

function Get-Weather {
    param (
        [Parameter(Position = 0)]
        [ValidateSet("Sunny", "Cloudy", "Rainy")]
        [string]$Weather
    )

    Write-Host "Today's weather is: $Weather"
}

Get-Weather -Weather "Sunny"
Including Input with a Parameter

In this example, we have a Get-Weather function that accepts a -Weather parameter. The ValidateSet attribute is applied to the $Weather parameter, specifying a restricted set of valid values: “Sunny”, “Cloudy”, and “Rainy”.

When calling the Get-Weather function and passing a value to the -Weather parameter, PowerShell automatically validates the input against the defined set. If the provided value matches one of the valid options, the script executes accordingly. If an invalid value is provided, PowerShell throws an error.

In the example, we pass the value “Sunny” to the -Weather parameter when calling the function. Since “Sunny” is a valid option, the script outputs “Today’s weather is: Sunny” using the Write-Host command.

Case Sensitivity with PowerShell ValidateSet 

By default, the ValidateSet attribute in PowerShell is case-insensitive, meaning it treats input values as case-insensitive when validating against the specified set. However, if you want to make it case-sensitive, you can achieve this by defining a custom validation function. Here’s an example:

function Get-Weather {
    param (
        [Parameter(Position = 0)]
        [ValidateScript({
            $validValues = "Sunny", "Cloudy", "Rainy"
            $inputValue = $_
            $caseSensitive = $true

            if ($caseSensitive) {
                $validValues -contains $inputValue
            } else {
                $validValues -contains $inputValue.ToUpper()
            }
        })]
        [string]$Weather
    )

    Write-Host "Today's weather is: $Weather"
}

Get-Weather -Weather "sunny"   # This will throw an error
Case Sensitivity with PowerShell ValidateSet 

In this example, we define a custom validation script within the ValidateScript attribute applied to the $Weather parameter. The script checks if the input value ($inputValue) is present in the set of valid values ($validValues).

To make the validation case-sensitive, we introduce the $caseSensitive variable and set it to $true. Within the validation script, we use conditional logic to determine if we should compare the input value with the valid values as is or in uppercase (using.ToUpper()).

Using the Tab Completion feature

In PowerShell, tab completion is a helpful feature that allows you to quickly and easily complete commands, parameter names, file and folder paths, and more by pressing the Tab key. It saves time and reduces the chances of making typing errors.

Tab completion works by automatically suggesting or completing the available options based on what you have typed. Here are some common scenarios where tab completion can be used:

  1. Command completion: When typing a command, you can press Tab after typing a few characters, and PowerShell will suggest available commands that match those characters. You can then continue typing or press Tab again to complete the command.
  2. Parameter completion: When providing parameters for a command, you can press Tab after typing the parameter name (preceded by a hyphen), and PowerShell will suggest available parameter names that match what you have typed. This helps ensure you provide the correct parameter names and avoid typos.
  3. Path completion: When working with file and folder paths, you can use tab completion to navigate through the file system. By typing part of a path and pressing Tab, PowerShell will suggest matching file and folder names in the current directory or the specified path. This makes it easier to navigate and select the desired file or folder.

Tab completion is especially useful when dealing with long or complex command names, parameter names, or file paths. It helps prevent mistakes, improves efficiency, and provides a more seamless and intuitive PowerShell experience.

ValidateSet Cmdlet in PowerShell 6.1

The ErrorMessage Property

In PowerShell 6.1 and later versions, the ValidateSet attribute provides an ErrorMessage property that allows you to customize the error message displayed when the validation fails. This feature is useful when you want to provide more specific and informative error messages to the user.

Here’s an example that demonstrates the usage of the ErrorMessage property with the ValidateSet attribute:

function Get-Fruit {
    param (
        [Parameter(Position = 0)]
        [ValidateSet("Apple", "Banana", "Orange", ErrorMessage = "Please enter a valid fruit: Apple, Banana, or Orange.")]
        [string]$Fruit
    )

    Write-Host "You selected: $Fruit"
}

Get-Fruit -Fruit "Grapes"   # This will display a custom error message
The ErrorMessage Property

In this example, the ValidateSet attribute is applied to the $Fruit parameter of the Get-Fruit function. The valid options for the Fruit parameter are “Apple”, “Banana”, and “Orange”. If the user provides an invalid value, such as “Grapes”, PowerShell will display the custom error message defined in the ErrorMessage property.

PowerShell Classes

In PowerShell 6.1 and later versions, the ValidateSet attribute can be used in PowerShell classes to enforce validation on class properties. This attribute allows you to define a set of valid values for a property, ensuring that only those values can be assigned to it.

Here’s an example that demonstrates the usage of the ValidateSet attribute in a PowerShell class:

class Car {
    [ValidateSet("Sedan", "SUV", "Convertible")]
    [string]$Type

    Car([string]$type) {
        $this.Type = $type
    }
}

$car1 = [Car]::new("Sedan")
$car2 = [Car]::new("Truck")  # This will throw a validation error
PowerShell Classes

In this example, the Car class has a property called Type, which is annotated with the ValidateSet attribute. The valid options for the Type property are “Sedan”, “SUV”, and “Convertible”. When an instance of the Car class is created, the assigned value for the Type property is validated against the defined set of valid values.

If an invalid value is assigned to the Type property, PowerShell will throw a validation error, indicating that the assigned value is not among the valid options.

Using Classes for a ValidateSet Value List

Making Data Sources for the Class

When using classes with the ValidateSet attribute, you can create data sources to define the valid value list for the attribute. Data sources provide a flexible way to manage and update the valid values separately from the class definition itself.

Here’s an example that demonstrates how to create data sources for a class with ValidateSet attribute values:

class Car {
    [ValidateSet([Car]::GetCarTypes())]
    [string]$Type

    static [string[]] GetCarTypes() {
        # Simulating data retrieval from a data source
        $types = "Sedan", "SUV", "Convertible"
        return $types
    }
}

$car1 = [Car]::new()
$car1.Type = "Sedan"  # Valid value
$car1.Type = "Truck"  # Invalid value, throws a validation error
Making Data Sources for the Class

In this example, the Car class has a property called Type, which uses the ValidateSet attribute. Instead of directly specifying the valid values within the attribute, a static method GetCarTypes() is defined within the class.

Including Class to Script

When using classes to define a ValidateSet value list, you can include the class directly in your PowerShell script to ensure that the required data is available at runtime. This approach allows you to have self-contained scripts without the need for external dependencies.

Here’s an example that demonstrates including a class in a script to provide the valid value list for the ValidateSet attribute:

class Car {
    [ValidateSet([Car]::GetCarTypes())]
    [string]$Type

    static [string[]] GetCarTypes() {
        $types = "Sedan", "SUV", "Convertible"
        return $types
    }
}

#Rest of your script here
Including Class to Script

In this example, the Car class is defined within the script itself. The ValidateSet attribute for the $Type property references the GetCarTypes() static method from the same Car class. This ensures that the valid value list is available when the script is executed.

By including the class directly in the script, you eliminate the need for external dependencies or separate class files. This makes your script self-contained and easier to distribute or share with others.

You can then continue writing the rest of your script below the class definition, utilizing the Car class with its ValidateSet attribute to enforce validation on the $Type property.

Script Executions

When using classes for a ValidateSet value list, it’s important to understand how the script executions affect the availability of the class and its valid value list.

  1. Interactive Execution: If you run the script in an interactive session, such as typing the commands directly in the PowerShell console, the class and its valid value list will be available for the duration of that session. You can define and use the class as needed, and the valid value list will be accessible during the execution of the script.
  2. Script Execution: If you run the script by executing it as a standalone script file, the class and its valid value list will be available for the duration of that script’s execution. The script will load the class, define the valid value list, and you can use it within the script. However, once the script execution is completed, the class and its valid value list will no longer be available in the session.
  3. Module Execution: If you create a PowerShell module that includes the class with the ValidateSet attribute, the class and its valid value list will be available whenever the module is imported or loaded. The module can be imported into different sessions or scripts, allowing you to use the class and its valid value list across multiple executions.

It’s important to note that when using classes for a ValidateSet value list, the availability of the class and its valid value list is tied to the scope and lifespan of the execution environment. It may not persist beyond the current session or script execution unless you take appropriate measures, such as creating a module or redefining the class for each script execution. 

In conclusion, the ValidateSet attribute in PowerShell provides a robust mechanism for input validation, enhancing the reliability and usability of your scripts. With the knowledge gained from this article, you are now equipped to implement effective input validation using ValidateSet in your PowerShell scripts.