How to validate multiple items in a parameter using [ValidateScript]

If I have multiple computer names in the -ComputerName parameter of my advanced function, where one computer does not exist, the ValidateScript attribute doesn’t seem to realize that it is an array.

Here is my function:

[pre]

Function Test-ConnectionStatusBeforeDoingSomething
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)]
[ValidateScript({
$_ | Foreach-Object -Process {

Try
{
Test-Connection -ComputerName $_ -ErrorAction Continue -Verbose
}

Catch
{
Write-Warning -Message “$_ is not online!”
}
}
})]
[ValidateNotNullOrEmpty()]
$ComputerName
)

Begin {}

Process
{
Write-Output -Verbose “$ComputerName is online!”
}

End {}
}

Test-ConnectionStatusBeforeDoingSomething -ComputerName (‘TestSystem1’, ‘TestSystem2’)

[/pre]


For instance, if TestSystem1 is a legit system and it is online, the ValidateScript attribute will not move on to the Process block to produce the output, but it will if it is the ONLY item assigned to the $ComputerName variable.

How do I get the ValidateScript attribute to move onto the Process block for a legit system that is online, but produce an error for a system that is not?

 

Thank you

Unusual use of ValidateScript, really. ValidateScript is designed to be inclusive. If any item fails, it’s designed to prevent the script from being run. Also, ValidateScript is designed to throw unless you explicitly provide some output that can be interpreted as $true. I think it also processes each item individually, but if anything fails, everything is supposed to fail. That’s how parameter validation is – if you give it invalid parameters, the function is supposed to stop. If you’re working with errors you can handle, usually not the best call to put it in parameter validation.

If all you’re doing is a function to test if a computer is online or not, I’d move everything out of the ValidateScript. Then, I’d make this function simply return a $true or a $false value based on the computer’s connection status; it’s what the Test- verb is defined as doing. If you want to provide additional information I’d stick it in the verbose stream or something.

If, however… you want this command to also do other things and be able to simply skip the computers that aren’t online when it’s doing its thing, you still need to remove the ValidateScript approach. If any fail, the function will refuse to run, and I doubt that’s especially useful to you. Having a whole function just to test the connection status isn’t really needed, especially since Test-Connection has a -Quiet parameter that does in fact just return $true or $false.

So… going on that assumption, here’s how I’d look at it:

https://gist.github.com/vexx32/9f86d20e8026ab337693ce7f2dee9303

https://social.technet.microsoft.com/Forums/de-DE/a47fb2e4-06d7-4a65-97b9-1a01bb0fae65/how-to-validate-multiple-items-in-a-parameter-using-validatescript?forum=winserverpowershell

I was just playing with the ValidateScript to see if it could do something like this, no worries.

Thanks

Example I gave to someone who was looking at this use case.

$ValidateSet =   @('Banana','Apple','PineApple') # (Get-Content -Path 'E:\Temp\FruitValidationSet.txt')

function Test-LongValidateSet
{
    [CmdletBinding()]
    [Alias('tlfvs')]

    Param
    (
        [ValidateScript({
			if ($ValidateSet -contains $PSItem) {$true}
			else { throw $ValidateSet}})]
        [String]$Fruit
    )

	"The selected fruit was: $Fruit"
}

# Results - provide intellisense for the target $ValidateSet
Test-LongValidateSet -Fruit Apple
Test-LongValidateSet -Fruit Dog

# Results
The selected fruit was: Apple

Test-LongValidateSet -Fruit Dog
# Results

Test-LongValidateSet : Cannot validate argument on parameter 'Fruit'. Banana Apple PineApple
At line:1 char:29