Home > Enterprise >  How to use try/catch with validatepattern using parameters?
How to use try/catch with validatepattern using parameters?

Time:12-01

Basically, I need to be able to enter .'Nameofmyscript.ps1' 80, 80, 80, 90, 100, 100 (for example) in powershell. With these numbers, the script will do something with them. I just need to be able to type them in how I said above.

I am unable to do this without using a parameter, so I was wondering if there's a way to add a parameter in this. Since in my current script, it only accepts the integers I enter in the actual code.

*Also sorry if my powershell language is a bit messed up, I'm pretty new still. Thanks in advance for any help!

What I have so far:

try 
    {
    [ValidatePattern("^\d $")] 
    [int] $G1 = 88
    [int] $G2 = 77
    [int] $G3 = 66
    [int] $G4 = 55
    [int] $G5 = 44
    [int] $G6 = 33
    
} catch [System.Management.Automation.ValidationMetadataException] {
    [int]$G1 = 10
} catch {
    Write-Host "Please make sure you are only inputting integers."
    Exit
}   

Write-Host $G1 
Write-Host $G2
Write-Host $G3 
Write-Host $G4
Write-Host $G5 
Write-Host $G6

CodePudding user response:

The [ValidateXXX()] attribute declaration is used on parameters in a param(..) block.
What you describe is a script that takes 6 integer parameter values (optional with default values).
Because these are defined as [int], there is no reason to use [ValidatePattern("^\d $")] as if they were strings.. after all, an integer is always numeric.

What you could do is [ValidateRange(min, max)] to make sure each parameter is within an expected range of values, or [ValidateScript({..})] for instance to check if the given value is less than or greater than some value. (for that see the last example parameter $G6)

If validation fails an exception is thrown and the script stops there.

Try starting your script with

param (
    [ValidateRange(80, 90)]  # this ensures the value of param $G1 must be between 80 and 90 (inclusive)
    [int]$G1 = 88,
    [ValidateRange(70, 80)]  # this ensures the value of param $G2 must be between 70 and 80 (inclusive)
    [int]$G2 = 77,
    [ValidateRange(60, 70)]  # this ensures the value of param $G3 must be between 60 and 70 (inclusive)
    [int]$G3 = 66,
    [ValidateRange(50, 60)]  # this ensures the value of param $G4 must be between 50 and 60 (inclusive)
    [int]$G4 = 55,
    [ValidateRange(40, 50)]  # this ensures the value of param $G5 must be between 40 and 50 (inclusive)
    [int]$G5 = 44,
    [ValidateScript({$_ -lt 40})]  # this ensures the value of param $G6 must less than 40
    [int]$G6 = 33
)

# do something with the values
Write-Host $G1 
Write-Host $G2
Write-Host $G3 
Write-Host $G4
Write-Host $G5 
Write-Host $G6

If you want your own error message if the validfation fails, you need to use the ValidateScript option like:

[ValidateScript({
    if ($_ -lt 40) { $true }  # all is well
    else { throw "Value $_ is invalid. You must enter a value less than 40" }
})]
[int]$G6 = 33

or when defining the parameter as string where you want to receive an integer value, you could do:

[ValidateScript({
    if ($_ -match '^\d $') { $true }  # all is well
    else { throw "Value $_ is invalid. You must enter digits only" }
})]
[string]$G6

CodePudding user response:

Instead of using [validate...] attributes which will throw and stop the script when a condition is not met, if you're looking to have the user input the parameters until all are integers then this would need to be validate within the script itself.

In this case, this param(...) will allow any kind of input and all validation is done in the begin {...} block. If an invalid input is found (-notmatch '^\d $') keep asking for a new input until the pattern matches all digits or the user decides to abort the script.

Lastly, after all validation is done, convert the parameter to [int].

[cmdletbinding()]
param(
    $G1 = 88,
    $G2 = 77,
    $G3 = 66,
    $G4 = 55,
    $G5 = 44,
    $G6 = 33
)

begin
{
    while($PSBoundParameters.Values -notmatch '^\d $')
    {
        foreach($key in $PSBoundParameters.Keys)
        {
            if($PSBoundParameters[$key] -notmatch '^\d $')
            {
                "Invalid input for Parameter '$key'. Only integers are allowed." |
                Write-Warning

                :inner while($true)
                {
                    if(($choice = Read-Host 'Try again? (Y / N)') -notmatch '^y|n$')
                    {
                        continue
                    }

                    switch ($choice)
                    {
                        Y { 
                            $newInput = Read-Host "Provide new input for Parameter '$key'"
                            $PSBoundParameters[$key] = $newInput
                            break inner
                        }
                        N {
                            'Aborting...'
                            exit
                        }
                    }
                }
            }
        }
    }

    $PSBoundParameters.Keys.ForEach({
        Get-Variable $_ | Set-Variable -Value ([int]$PSBoundParameters[$_])
    })
}

process
{
    # Just for testing
    Get-Variable G* | Select-Object Name, Value, @{
        name = 'IsInt'
        expression = {$_.Value -is [int]}
    }
    
    # Code goes here...
}

Sample Input / Output:

PS /> ./script.ps1 zxc 80 asd 123 45 66

WARNING: Invalid input for Parameter 'G1'. Only integers are allowed.
Try again? (Y / N): y
Provide new input for Parameter 'G1': 123
WARNING: Invalid input for Parameter 'G3'. Only integers are allowed.
Try again? (Y / N): y
Provide new input for Parameter 'G3': 456

Name Value IsInt
---- ----- -----
G1     123  True
G2      80  True
G3     456  True
G4     123  True
G5      45  True
G6      66  True
  • Related