I'm trying to create a powershell function that validates users names and if a tech inputs the wrong character, I want it to throw an error message as to why it was wrong and restart the script for them to make the choice again.
So far I have this
Running VSCode with Powershell Extension 2022.8.5
function stringTest {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateLength(4,15)]
[ValidatePattern('^[a-zA-Z0-9-_] $')]
[string] $alphaTest
)
Write-Host $alphaTest
}
$writeHere = Read-Host "UserName: "
stringTest($writeHere)
Output:
UserName: doej
doej
This works fine, but I want to try and add Custom error messages using the ErrorMessage
within Validate Pattern. So I would try this
function stringTest {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateLength(4,15)]
[ValidatePattern({$pattern = "^[a-zA-Z0-9-_] $([Regex]::escape($pattern))\s"
if ($_ -in $pattern ) {return $true}
throw "$_ is not a valid character. Valid characters are: '$($pattern -join ',')'"
})]
[string] $alphaTest
)
Write-Host $alphaTest
}
$writeHere = Read-Host "UserName: "
stringTest($writeHere)
But now my Validate doesn't actually validate anymore? I try the same name or anything different that "should" be valid
Cannot validate argument on parameter 'alphaTest'. The argument "doej" does not match the "$pattern = | "^[a-zA-Z0-9-] $([Regex]::escape($pattern))\s" if ($ -in $pattern ) {return $true} throw "$_ is not a valid | character. Valid characters are: '$($pattern -join ',')'" " pattern. Supply an argument that matches "$pattern = | "^[a-zA-Z0-9-] $([Regex]::escape($pattern))\s" if ($ -in $pattern ) {return $true} throw "$_ is not a valid | character. Valid characters are: '$($pattern -join ',')'" " and try the command again.
From the looks of it, it's trying to match the regex pattern exactly instead of working the way before. Any help would be greatly appreciated or pointing me in the write direction for this.
CodePudding user response:
You can have your custom attribute declaration using a class
as described in this answer, both ValidatePattern
and ValidateLength
attribute declarations inherit from the same base class, ValidateArgumentsAttribute
Class.
You can also use ValidateScript
as described in mklement0's answer.
Here is one example of how the custom class
would look like:
class ValidateCustomAttribute : Management.Automation.ValidateEnumeratedArgumentsAttribute {
hidden [int] $Min
hidden [int] $Max
hidden [string] $Pattern
ValidateCustomAttribute() { }
ValidateCustomAttribute([scriptblock] $Validation) {
$this.Min, $this.Max, $this.Pattern = & $Validation
}
[void] ValidateElement([object] $Element) {
if($Element.Length -lt $this.Min -or $Element.Length -gt $this.Max) {
$errorRecord = [Management.Automation.ErrorRecord]::new(
[Exception] ('Invalid Length! Must be between {0} and {1}.' -f $this.Min, $this.Max),
'InvalidLength',
[Management.Automation.ErrorCategory]::InvalidArgument,
$Element
)
throw $errorRecord
}
if($Element -notmatch $this.Pattern) {
$errorRecord = [Management.Automation.ErrorRecord]::new(
[Exception] ('Invalid Argument! Does not match {0}.' -f $this.Pattern),
'PatternNotMatch',
[Management.Automation.ErrorCategory]::InvalidArgument,
$Element
)
throw $errorRecord
}
}
}
As for the implementation:
function Test-Attribute {
param(
[ValidateCustomAttribute({ 2, 10, '^[a-zA-Z0-9-_] $' })]
[object] $Test
)
$Test
}
This syntax is also valid for the attribute declaration:
[ValidateCustomAttribute(Min = 2, Max = 10, Pattern = '^[a-zA-Z0-9-_] $')]
And the testing:
PS /> Test-Attribute 'hello???'
Cannot validate argument on parameter 'Test'. Invalid Argument! Does not match ^[a-zA-Z0-9-_] $.
PS /> Test-Attribute 'somelongstring'
Cannot validate argument on parameter 'Test'. Invalid Length! Must be between 2 and 10.
PS /> Test-Attribute hello
hello
As aside, the pattern can be reduced to just ^[\w-] $
.