Reputation: 1122
I know you can declare an integer parameter that only accepts values within a specific range:
[Parameter()][ValidateRange(1024,66535)]$Port
Is it possible to validate parameter input for several ranges? For example, say I want to allow port inputs to be 1 through 80, 135 through 445, and 1024 through 65535, I could do it with:
[Parameter()][ValidateRange(1,66535)]$Port
if ((($Port -gt 80) -and ($Port -lt 135)) -or (($Port -gt 445) -and ($Port -lt 1024))) {
Write-Error "Incorrect input, please enter a value between 1-80, 135-445, or 1024-65535"
break
}
However that doesn't strike me as a particularly neat way of doing things. ValidateSet()
also can't take number ranges like 1024..65535. Anyone have a better idea of input validation for multiple integer ranges?
Upvotes: 3
Views: 1289
Reputation: 61313
You can definitely implement your custom ValidateRange
attribute declaration by creating a class
that inherits from the ValidateEnumeratedArgumentsAttribute
Class. Here is a little example:
class ValidateCustomRange : Management.Automation.ValidateEnumeratedArgumentsAttribute {
[void] ValidateElement([object] $Element) {
if($Element -gt 80 -and $Element -lt 135 -or $Element -gt 445 -and $Element -lt 1024) {
throw [Management.Automation.MetadataException]::new(
'Invalid range! Must be ...your call here :)'
)
}
}
}
function Test-Range {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[ValidateCustomRange()]
[int] $Port
)
}
Test-Range 80 # All good!
Test-Range 81 # Error
Upvotes: 4
Reputation: 440677
To complement Santiago Squarzon's helpful answer with an alternative that may be of interest for making a function or script self-contained:
Using the [ValidateScript()]
allows you to specify a script block for validation, in which you can refer to the argument given via $_
That way you don't need to declare a separate class, which in a stand-alone script you wouldn't be able to reference in your script's param(...)
block, which must come first in the file.
Conversely, however, if you're authoring a module, where you can package your classes along with the exported functions that use them, Santiago's ValidateEnumeratedArgumentsAttribute
-based class
solution may be preferable.
A solution that also works in Windows PowerShell (throw
is used to provide a meaningful custom error message):
function foo {
param(
[ValidateScript({
if ($_ -in 1..80 + 135..445 + 1024..65535) { return $true }
throw "Value $_ is not between 1 and 80, 135 and 445, or 1024 and 65535."
})]
$Port
)
$Port # Sample output: echo the port given, if it passed validation
}
foo 10 # OK
foo 100 # Fails validation.
A simplified solution that requires PowerShell (Core) 7+, where you can now use an ErrorMessage
property to provide a custom error message:
# PS v7+, using the ErrorMessage property.
function foo {
param(
[ValidateScript(
{ $_ -in 1..80 + 135..445 + 1024..65535 },
ErrorMessage = 'Value {0} is not between 1 and 80, 135 and 445, or 1024 and 65535.'
)]
$Port
)
$Port # Sample output: echo the port given, if it passed validation
}
foo 10 # OK
foo 100 # Fails validation.
Upvotes: 2