PowerShell Validate Parameter Input with ValidateScript

PowerShell Validate Parameter Input with ValidateScript

PowerShell Tips Editor 3 min read
PowerShell Validate Parameter Input with ValidateScript

Parameter validation catches bad inputs before your function’s logic runs. [ValidateSet()] handles fixed option lists and [ValidateRange()] handles numeric bounds, but many real-world validation requirements — “this path must exist and be writable,” “this string must be a valid IP address,” “this number must be odd” — require arbitrary code logic. PowerShell ValidateScript parameter validation runs any script block at parameter binding time, giving you complete flexibility to validate anything.

Quick Answer / TL;DR

Add [ValidateScript({ your_test_here })] before a parameter. The script block must return $true for validation to pass, or throw an exception with a custom message. Use $_ to reference the parameter value inside the block.

ValidateScript Syntax

The [ValidateScript()] attribute takes a script block that receives the proposed parameter value as $_. If the block returns a truthy value, the parameter is accepted. If it returns $false, $null, or throws, PowerShell rejects the binding with an error. The attribute must be placed immediately before the parameter declaration inside the param block.

# Basic ValidateScript — value must be positive
function Set-BufferSize {
    [CmdletBinding()]
    param(
        [ValidateScript({
            if ($_ -gt 0) { $true }
            else { throw "BufferSize must be greater than 0. You provided: $_" }
        })]
        [int]$BufferSize
    )
    Write-Host "Buffer size set to $BufferSize"
}

Set-BufferSize -BufferSize 1024    # Passes
Set-BufferSize -BufferSize -5      # Throws: BufferSize must be greater than 0

Validate File Path Exists

One of the most common ValidateScript patterns: ensure a file path actually exists before the function runs. This prevents the function body from receiving a nonexistent path and failing with a cryptic error deep in its logic.

function Import-DataFile {
    [CmdletBinding()]
    param(
        [ValidateScript({
            if (Test-Path -Path $_ -PathType Leaf) { $true }
            else { throw "File not found: '$_'. Provide a valid file path." }
        })]
        [string]$FilePath,

        [ValidateScript({
            if (Test-Path -Path $_ -PathType Container) { $true }
            else { throw "Directory not found: '$_'." }
        })]
        [string]$OutputDirectory
    )

    Write-Verbose "Processing $FilePath -> $OutputDirectory"
    Import-Csv -Path $FilePath | Export-Csv -Path "$OutputDirectory\output.csv" -NoTypeInformation
}

Validate IP Address Format

Validate that a string is a well-formed IPv4 address using [System.Net.IPAddress]::TryParse(). This is more reliable than a regex because it also validates the numeric range of each octet.

function Connect-ToServer {
    [CmdletBinding()]
    param(
        [ValidateScript({
            $ip = $null
            if ([System.Net.IPAddress]::TryParse($_, [ref]$ip)) { $true }
            else { throw "'$_' is not a valid IPv4 or IPv6 address." }
        })]
        [string]$IPAddress,

        [ValidateRange(1, 65535)]
        [int]$Port = 443
    )

    Write-Host "Connecting to $IPAddress`:$Port"
}

Connect-ToServer -IPAddress '192.168.1.100' -Port 8080   # Valid
Connect-ToServer -IPAddress '999.999.999.999'             # Throws: not valid

Custom Error Messages with Throw

The default error message from a failed ValidateScript is generic and confusing: “Cannot validate argument on parameter ‘X’. The script block returned false…” Use throw inside the script block to provide a clear, actionable error message instead.

function New-DatabaseBackup {
    [CmdletBinding()]
    param(
        [ValidateScript({
            if ($_ -match '^\w+$') { $true }
            else {
                throw "DatabaseName '$_' contains invalid characters. " +
                      "Use only letters, numbers, and underscores."
            }
        })]
        [string]$DatabaseName,

        [ValidateScript({
            $space = (Get-PSDrive ($_ -replace '.*:', '')[0]).Free
            if ($space -gt 5GB) { $true }
            else { throw "Insufficient disk space. Need 5GB, have $([math]::Round($space/1GB,1)) GB free." }
        })]
        [string]$BackupPath = 'C:\Backups'
    )

    Write-Host "Backing up $DatabaseName to $BackupPath"
}

Combine Multiple Validators

Stack multiple validation attributes on the same parameter for layered validation. PowerShell evaluates them in order — the first failing validator stops execution with its error. Combine [ValidateNotNullOrEmpty()], [ValidatePattern()], and [ValidateScript()] for comprehensive parameter guarding.

function Set-UserEmail {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern('^[\w.%+\-]+@[\w.\-]+\.[a-zA-Z]{2,}$')]
        [ValidateScript({
            # Additional check: domain must be contoso.com
            if ($_ -like '*@contoso.com') { $true }
            else { throw "Email must be a contoso.com address. Got: '$_'" }
        })]
        [string]$EmailAddress
    )

    Write-Host "Setting email to: $EmailAddress"
}

ValidateScript vs ValidatePattern

[ValidatePattern()] accepts a regex string and is fast and simple for format validation. [ValidateScript()] accepts any PowerShell code and is necessary when validation requires: file system checks, external lookups, arithmetic conditions, or multi-condition logic. Use ValidatePattern for simple format matching and ValidateScript for anything requiring logic or external state.

# ValidatePattern: good for fixed formats
[ValidatePattern('^\d{4}-\d{2}-\d{2}$')]
[string]$DateString    # e.g. 2024-03-15

# ValidateScript: needed when logic is required
[ValidateScript({
    $date = $null
    if ([datetime]::TryParse($_, [ref]$date) -and $date -gt [datetime]::Now) { $true }
    else { throw "Date must be a valid future date." }
})]
[string]$FutureDate

Common Errors and Fixes

  • Return $true at end — ValidateScript must return truthy or throw. If your script block ends with a statement that returns $null or nothing (like Write-Host), validation fails silently. Ensure the block explicitly returns $true as the last expression when validation passes. Every code path must either return a truthy value or throw.
  • Error message from ValidateScript is generic by default. Without a throw statement, the error reads “The ValidateScript attribute cannot be validated.” Use throw "your message" inside the script block to replace the generic message with something actionable for the user calling your function.

Related Cmdlets / See Also

Wrapping Up

ValidateScript fills the validation gap between simple attribute validators and full function body logic. Use it for file existence checks, address format validation, range constraints beyond ValidateRange, and any condition requiring PowerShell code. Always use throw with a descriptive message rather than returning $false — clear error messages are a hallmark of professional functions.

Send-Item -To