[Solved}Understanding use of PSCustomobject

upate:

$computers= "localhost"

  
  foreach ($pc in $computers){
  
        $test_connection = Test-Connection -ComputerName $pc -Count 1 -ErrorAction Continue
        $test_netconnection = Test-NetConnection $pc -Port 1433 -ErrorAction Continue
        
        #i had to delete these two lines and it make the script working, also, change the count to 1 in the upper variable
        #Test-Connection -ComputerName $pc -Count 3 -ErrorAction Continue
        #Test-NetConnection -ComputerName $pc -ErrorAction Continue
        [pscustomobject] @{
                           LocalPC             =$test_connection.PSComputerName;
                           Destination         =$test_connection.Remotecomputer
                          'Problematic-server'  =$test_connection.IPV4Address
                           Bytes               =$test_connection.Bytes
                           Time                =$test_connection.Time
                           MyLocalIP           =$test_netconnection.SourceAddress.IPv4Address
                           RemotePort          =$test_netconnection.RemoteAdress
                           ResolvedAddresses   =$test_netconnection.ResolvedAddresses
                           }
                            }
                            

Hi Lev,

I think you could simplify your code by only having one foreach loop:

foreach ($pc in $Computers)
{
    $tc=try{Test-Connection $pc -Count 1 -ErrorAction stop} catch {Write-Warning "$pc is not responding!"}
    if ($tc){
        $tn=Test-NetConnection $pc -Port 1433
        [pscustomobject]@{
            ComputerName = $tc.PSComputerName
            ProblematicServer=$tc.Address
            BufferSize=$tc.buffersize
            MyLocalIPAdress=$tn.SourceAddress
            RemoteAddress=$tn.RemoteAddress
            RemotePort=$tn.RemotePort
            TcpTestSucceeded=$tn.TcpTestSucceeded
        }
    }
}

Output is a PSObject for each machine you can contact. You can format the PSObject to any output you like. Furthermore you might want to experiment with formatting your code as an advanced function and let the PSObject be the output.

In order for Try-Catch to trip, the error must be terminating. To ensure the error is terminating, you need to be using -ErrorAction Stop. Additionally, you’ll need to put the Try-Catch inside the loop, not outside it; you’ll probably get some very confusing behaviour doing it the way you’ve set it up.

I did a foreach loop, but i did it twice, didn’t thought about using it in your way
i’m going to separate your code to understand better (and learn on the way :slight_smile:

this is all one variable, i didn’t knew that you can declare a variable in that way
(i’m in scripting a bit more than one month, so i’m learning each day something new through experience)

$tc=try{Test-Connection $pc -Count 1 -ErrorAction stop} catch {Write-Warning "$pc is not responding!"}

and here you’ve used Splatting

    if ($tc){
        $tn=Test-NetConnection $pc -Port 1433
        [pscustomobject]@{
            ComputerName = $tc.PSComputerName
            ProblematicServer=$tc.Address
            BufferSize=$tc.buffersize
            MyLocalIPAdress=$tn.SourceAddress
            RemoteAddress=$tn.RemoteAddress
            RemotePort=$tn.RemotePort
            TcpTestSucceeded=$tn.TcpTestSucceeded
        }
    }
}

do i need to add “else” condition to the “IF” in order to get the error?

one more quastion,
if i’ll take

$tn=Test-NetConnection $pc -Port 1433

i can’t paste the code :\ it’s allowing me only few lines

The thing is that i have 3 servers and i don’t want that it will stop if only one server is down
that’s why i’ve used -ea continue

so i need to put the “catch” inside the “try” loop?

You don’t need an else section.

If you want to pipe test-netconnection to Select-Object, you just remove $tn= from the beginning of the line.

and i do it like that:

if ($tc){
            [pscustomobject]@{
            ComputerName = $tc.PSComputerName
            ProblematicServer=$tc.Address
            BufferSize=$tc.buffersize
            MyLocalIPAdress=$tn.SourceAddress
            RemoteAddress=$tn.RemoteAddress
            RemotePort=$tn.RemotePort
            TcpTestSucceeded=$tn.TcpTestSucceeded
        }
    }   Test-NetConnection $pc -Port 1433 |select-object
}

but if i remove the $tn variable, what will be used in the splatting table?
i don’t think that it’ll work

also i’ve noticed that you already used a custom property, and there is no need to make a new property

this is a very interesting approach, it’s as you said “i can make any output that i want” so actually i don’t need to pipe it into select-object

i think just a bit of commenting in here will help

#loop through each computer within computers
foreach ($pc in $Computers)
{
#$tc will contain the pc information if successfull, if pc is offline, $tc will be empty
    $tc=try{Test-Connection $pc -Count 1 -ErrorAction stop} catch {Write-Warning "$pc is not responding!"}
#check contents of $tc, if empty do nothing, if has contents, test connection again to be able to splat information
    if ($tc){
        $tn=Test-NetConnection $pc -Port 1433
        [pscustomobject]@{
            ComputerName = $tc.PSComputerName
            ProblematicServer=$tc.Address
            BufferSize=$tc.buffersize
            MyLocalIPAdress=$tn.SourceAddress
            RemoteAddress=$tn.RemoteAddress
            RemotePort=$tn.RemotePort
            TcpTestSucceeded=$tn.TcpTestSucceeded
        }
    }
}

-ErrorAction Stop will only halt the script if it is not caught with a catch{} block. An ErrorAction value of Stop turns all errors into terminating errors, but what happens when they’re caught is still up to you – you can choose to log them and keep processing anyway, if that’s what you want.

If the code that raised the terminating error is within a try block, then the following catch code will execute, followed by one of two things:

The code will continue from where it left off (default behaviour), or it will stop all actions in the present set and resume the script from the next set, if one exists (nonstandard). The latter behaviour has to be deliberately selected by specifying the break keyword in the catch block:

# non terminating catch block
foreach ($item in $things) {
    try {
        Test-Connection -ComputerName 'TotallyNotReal' -ErrorAction Stop
    }
    catch {
        $Errors += $_
        # this keyword isn't necessary, but it is perfectly allowable to explicitly define the action following the catch
        continue 
    }
}

#terminating catch block
foreach ($item in $things) {
    try {
        Test-Connection -ComputerName 'TotallyNotReal' -ErrorAction Stop
    }
    catch {
        $Errors += $_
        # to select the terminating behaviour, the break keyword is necessary
        break
    }
}

Basically, all “-ErrorAction Stop” is doing for most purposes is ensuring you can catch it in the first place and let you do what you want with it. If you specify Continue instead, the catch block will never be able to trigger.

If you want to use Select-Object, you wouldn’t use the splatting bit. Both techniques creates a new PS object.

Often you would do something like:
$obj = [PSCustomObject]@{…

Then you can do:
$obj | Formst-Table -autosize
later

OK,
i think i got it :slight_smile:

Acording to your code, i need to make one “try\catch” block with two Foreach statements One for Test-connection and one for Test-netconnection (both of them with either -ea “stop” or “continue”)

Ok, i will try to do it your way, i have to understand the logic in order to memorise this.

Thanks alot David

somthing that i don’t understand,
in your script you use the command

$tn=Test-NetConnection $pc -Port 1433

before the splatting.

update:i’ve updated the post name and the first post to

Well, Axel’s code will provide you with a pscustom object with the data as presented.
It is up to you to do something with that object’s data. Just make sure you do it within the foreach loop or you lose the data when it connects to the next machine.

As far as the splatting, you are basically building the same types of objects. It is just a question of what you do with the object once created.

Neither approach is really “wrong”

If you want the try-catch to function, don’t use -ErrorAction Continue – it will prevent errors triggering the catch.

As for two loops… eh, you could do one, and have the first error simply trip the catch and go right on ahead to the next loop iteration, wouldn’t be a big deal, really. Basically as long as both commands are within the Try block, the first one to error out can make PS skip the rest, if that’s what you want it to do (so if it fails the connection completely, it doesn’t bother trying to do anything else with it).

Also – why are you using both Test-Connection and Test-NetConnection? Their function is pretty similar, after all.