Reputation: 14755
Is it possible to have ValidateScript
generate a custom error message when a test fails, like say Test-Path
?
Instead of this:
Test-Folder : Cannot validate argument on parameter 'Folder'. The "Test-Path $_ -Path Type Container" validation script for the argument with value "blabla" did not return a result of True. Determine why the validation script failed, and then try the comma and again.
It would be nice to have it report this instead in the $Error
variable:
The 'Folder' is not found, maybe there are network issues?
Code:
Function Test-Folder {
Param (
[parameter(Mandatory=$true)]
[ValidateScript({Test-Path $_ -PathType Container})]
[String]$Folder
)
Write-Host "The folder is: $Folder"
}
Workaround 1:
I could remove the Mandatory=$true
and change it as below. But this doesn't give me the correct Get-Help
syntax and doesn't do the Test-Path
validation, because it only checks if the parameter is present.
Function Test-Folder {
Param (
[parameter()]
[String]$Folder = $(throw "The $_ is not found, maybe there are network issues?")
)
Write-Host "The folder is: $Folder"
}
Workaround 2:
I found this workaround on a blog post, but the problem is that it generates two errors instead of one.
Function Test-Folder {
Param (
[parameter(Mandatory=$true)]
[ValidateScript({
if (Test-Path $_ -PathType Container) {$true}
else {Throw "The $_ is not found, maybe there are network issues?"}})]
[String]$Folder
)
Write-Host "The folder is: $Folder"
}
Workaround 3:
I could also try to make it more clear by adding a comment section. However, this is still not the desired result as the error needs to be readable to end users.
Function Test-Folder {
Param (
[parameter(Mandatory=$true)]
[ValidateScript({
# The folder is not found, maybe there are network issues?
Test-Path $_ -PathType Container})]
[String]$Folder
)
Write-Host "The folder is: $Folder"
}
Upvotes: 19
Views: 19422
Reputation: 701
You can just do
ValidateScript({Test-Path $_ -PathType Container}, ErrorMessage="Must exist")]
That gives you error messages like:
Cannot validate argument on parameter 'Folder'. Must exist
At least in current powershell versions (7.x at the time of writing this).
Generally, for you powershell-only devs, when you use attributes (stuff like [ValidateScript
), then you can sometimes also set additional properties with the syntax as above. To see which properties, you can just google for the name of the attribute postfixed with "Attribute", eg "ValidateScriptAttribute", and then look at the "Properties" section for all writeable properties.
Upvotes: 6
Reputation: 1
I am not sure.
A suggestion: maybe you want to just trap the error, and make your own message.
trap [Error.Type] {
@"
The message you want displayed.
With maybe some additional information.
I.e.: The full message itself: {0}' -f $_.Error.Message;
continue;
}
Upvotes: 0
Reputation: 8019
I think you've found the straightforward workarounds.
The parameter validation logic is extensible, but requires some C#. If you implement the abstract class System.Management.Automation.ValidateArgumentsAttribute, your implementation can throw a System.Management.Automation.ValidationMetadtaException that PowerShell will use to report the error, and you can naturally use any message you like when creating that exception.
Upvotes: 2
Reputation: 6293
Your ValidateScript
should look something like this:
[ValidateScript({
try {
$Folder = Get-Item $_ -ErrorAction Stop
} catch [System.Management.Automation.ItemNotFoundException] {
Throw [System.Management.Automation.ItemNotFoundException] "${_} Maybe there are network issues?"
}
if ($Folder.PSIsContainer) {
$True
} else {
Throw [System.Management.Automation.ValidationMetadataException] "The path '${_}' is not a container."
}
})]
That will give you a message like this:
Test-Folder : Cannot validate argument on parameter 'Folder'. Cannot find path '\\server\Temp\asdf' because it does not exist. Maybe there are network issues?
Or:
Test-Folder : Cannot validate argument on parameter 'Folder'. The path '\\server\Temp\asdf' is not a container.
If the older versions of PowerShell are throwing a double error, you may need to test inside the function:
Function Test-Folder {
Param (
[parameter(Mandatory=$true)]
[String]$Folder
)
try {
$Folder = Get-Item $_ -ErrorAction Stop
} catch [System.Management.Automation.ItemNotFoundException] {
Throw [System.Management.Automation.ItemNotFoundException] "The '${Folder}' is not found, maybe there are network issues?"
}
if (-not $Folder.PSIsContainer) {
Throw [System.Management.Automation.ApplicationFailedException] "The path '${_}' is not a container."
}
Write-Host "The folder is: ${Folder}"
}
The part that I always hated in PowerShell was trying to figure out what error to catch; without catching all. Since I finally figure it out, here's how:
PS > Resolve-Path 'asdf'
Resolve-Path : Cannot find path '.\asdf' because it does not exist.
At line:1 char:1
+ Resolve-Path 'asdf'
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (asdf:String) [Resolve-Path], ItemNotFoundE
xception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.ResolvePathCommand
PS > $Error[0].Exception.GetType().FullName
System.Management.Automation.ItemNotFoundException
Upvotes: 17