Search code examples
powershellpowershell-3.0powershell-4.0

How to implement if statement inside a (after pipeline) ForEach-Object cmdlet?


Someone here helped me with some code and wrote this script (my original script had some problems).

Now I need to implement an if statement inside this ForEach-Object (to do something like this "if one of the servers is not alive Write-Host "blah blah"") without stopping so the try/catch does not fit here.

Here is the code (I've tried to play with that, but without any success).

$computers = "localhost"
foreach ($pc in $computers) {
    $test_netconnection = Test-NetConnection $pc -Port 1433
    Test-Connection -ComputerName $pc -Count 2 -Quiet | ForEach-Object {
        [PSCustomObject]@{
            LocalPC          = $_.PSComputerName
            'Tested-Server'  = $test_netconnection.ComputerName
            Bytes            = $_.buffersize
            Time             = $_.ResponseTime
            RemotePort       = $test_netconnection.RemotePort
            TcpTestSucceeded = $test_netconnection.TcpTestSucceeded
        }
    }
}

this is the correct output for a computer which is on the network

LocalPC Tested-Server Bytes Time RemotePort TcpTestSucceeded
------- ------------- ----- ---- ---------- ----------------
LEVL-01 localhost        32    0       1433            False
LEVL-01 localhost        32    0       1433            False

and this is the output for a computer which is not on the network

    test-Connection : Testing connection to computer 'localh0st' failed: No such host is known
   servers\Foreach-object.ps1:9 char:5
    +     test-Connection -ComputerName $pc -Count 2 |
    +     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : ResourceUnavailable: (localh0st:String) [Test-Connection], PingException
        + FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand

Instead of the red error, i need to make it show something like "the computer is not online" while the first output as left as is - that's why i try to implement the "IF" loop

Thanks alot for your help


Solution

  • From what I can see try/catch would do exactly what you're asking:

    try {
        Test-Connection -Computer $pc -Count 2 -EA Stop | ForEach-Object {
            [PSCustomObject]@{
                LocalPC          = $env:COMPUTERNAME
                'Tested-Server'  = $pc
                Bytes            = $_.buffersize
                Time             = $_.ResponseTime
                RemotePort       = $test_netconnection.RemotePort
                TcpTestSucceeded = $test_netconnection.TcpTestSucceeded
            }
        }
    } catch {
        "The computer $pc is not online."
    }
    

    However, personally I'd prefer keeping the output format for pingable and non-pingable hosts the same (with an additional column for the "online" status). For that use -ErrorAction SilentlyContinue to suppress the error, collect the result of Test-Connection in a variable, then build your custom object depending on whether or not that variable is empty.

    $test_connection = Test-Connection -Computer $pc -Count 2 -EA SilentlyContinue
    if ($test_connection) {
        $test_connection | ForEach-Object {
            [PSCustomObject]@{
                LocalPC          = $env:COMPUTERNAME
                'Tested-Server'  = $pc
                Online           = $true
                Bytes            = $_.buffersize
                Time             = $_.ResponseTime
                RemotePort       = $test_netconnection.RemotePort
                TcpTestSucceeded = $test_netconnection.TcpTestSucceeded
            }
        }
    } else {
        [PSCustomObject]@{
            LocalPC          = $env:COMPUTERNAME
            'Tested-Server'  = $pc
            Online           = $false
            Bytes            = $null
            Time             = $null
            RemotePort       = $test_netconnection.RemotePort
            TcpTestSucceeded = $test_netconnection.TcpTestSucceeded
        }
    }
    

    As a side-note, I do not recommend using derived information ($_.PSComputerName, $test_netconnection.ComputerName) where original information is available ($env:COMPUTERNAME, $pc`).