Reputation: 1184
I isolated some code and i have an unexpected behavior.
code:
$objects = @(
[pscustomobject]@{server="google.com"; some_other_props='some_str'},
[pscustomobject]@{some_other_props='some_str'},
[pscustomobject]@{server='google.com'; some_other_props='some_str'}
)
$objects | % {
try{
$result = Test-Connection $_.server
}catch [System.Management.Automation.ParameterBindingException] {
Write-Host "no server to ping"
}
if($result){
Write-Host ok
}
}
expected output:
ok
no server to ping
ok
real ouput:
ok
no server to ping
ok
ok
What am i doing wrong here? from where is the 3rd ok coming??
Upvotes: 0
Views: 187
Reputation: 27576
test-connection doesn't generate a script-terminating or command-terminating exception. Microsoft.com is classically unpingable.
try { test-connection microsoft.com -Count 1 } catch { 'no' }
test-connection : Testing connection to computer 'microsoft.com' failed: Error due to lack of resources
At line:1 char:6
+ try {test-connection microsoft.com -Count 1 } catch { 'no' }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (microsoft.com:String) [Test-Connection], PingException
+ FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand
You can use the -quiet option to return a boolean and use an if statement instead. Although even without the -quiet, it would work, since the standard output is non-null if the host is up.
if (test-connection microsoft.com -Count 1 -Quiet) {'yes'
} else {'no'}
no
Suprisigly, the '||' operator in Powershell 7 won't work here, because $? is always true after running the command.
test-connection microsoft.com -count 1 -quiet || 'no'
False
Upvotes: 0
Reputation: 61208
You need to add parameter -ErrorAction Stop
at the end of the Test-Connection
cmdlet in order to redirect both terminating and non-terminating errors to the catch
block.
Also, your code explicity catches one type of error, so if anything goes wrong, the code will output "no server to ping", even if that is not the case.
You can add another catch block to also display the other exception messages:
$objects = @(
[pscustomobject]@{server="google.com"; some_other_props='some_str'},
[pscustomobject]@{some_other_props='some_str'},
[pscustomobject]@{server='google.blah'; some_other_props='some_str'}
)
$objects | ForEach-Object {
$server = $_.server
try{
$result = Test-Connection $server -Count 1 -ErrorAction Stop
if ($result) {
Write-Host "Ping '$server': OK"
}
}
catch [System.Management.Automation.ParameterBindingException] {
Write-Host "No server to ping"
}
catch {
Write-Host "Ping '$server': ERROR: $($_.Exception.Message)"
}
}
Output:
Ping 'google.com': OK No server to ping Ping 'google.blah': ERROR: Testing connection to computer 'google.blah' failed: Host is unknown
Upvotes: 0
Reputation: 693
Your catch doesn't break the current execution, so your if statement will run regardless of if the code throws an exception.
Put your if statement at the bottom inside your catch instead.
$objects | % {
try{
$result = Test-Connection $_.server
if($result) {
Write-Host ok
}
} catch [System.Management.Automation.ParameterBindingException] {
Write-Host "no server to ping"
}
}
Upvotes: 2