1

I am having an issue with the way that my ping results "roll" out on the screen. I am using this code:

$servers = "192.168.2.10","192.168.2.80","192.168.2.254"
$collection = $()
foreach ($server in $servers)
{
    $status = @{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
    $testconnection = (Test-Connection $server -Count 1 -ea 0)
    $response = ($testconnection | select ResponseTime)
    if ($response)
    {
        $status["Results"] = "Up"
        $status["Responsetime"] = $response
    }
    else
    {
        $status["Results"] = "Down"
    }
    New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
    $collection += $serverStatus

}
$collection | Export-Csv -Path ".\ServerStatus.csv" -NoTypeInformation

I would to like create a loop for the ResponseTime The code that I am using now gives one response. When I give a count of 2, it prints the ResponseTime next to eachother per IP-adres.

Output:

TimeStamp                                             Responsetime                                          Results                                               ServerName                                           
---------                                             ------------                                          -------                                               ----------                                            
2014-10-22T23:30:17                                   {@{ResponseTime=6}, @{ResponseTime=4}}                Up                                                    192.168.2.10                                         
2014-10-22T23:30:18                                                                                         Down                                                  192.168.2.80                                         
2014-10-22T23:30:25                                   {@{ResponseTime=1}, @{ResponseTime=3}}                Up                                                    192.168.2.254

What I want is, that the script prints each ResponseTime under eachother like this:

TimeStamp               Responsetime              Results        ServerName                                           
---------               ------------              -------        ----------                                           
2014-10-22T23:11:50     @{ResponseTime=419}       Up             192.168.2.10                                         
2014-10-22T23:11:51     @{ResponseTime=415}       Up             192.168.2.10                                         
2014-10-22T23:11:51                               Down           192.168.2.80
2014-10-22T23:11:52     @{ResponseTime=470}       Up             192.168.2.254  
2014-10-22T23:11:52     @{ResponseTime=7}         Up             192.168.2.254

Or like this:

TimeStamp               Responsetime              Results        ServerName                                           
---------               ------------              -------        ----------                                           
2014-10-22T23:11:50     @{ResponseTime=419}       Up             192.168.2.10                                         
2014-10-22T23:11:51                               Down           192.168.2.80                                         
2014-10-22T23:11:51     @{ResponseTime=415}       Up             192.168.2.254
2014-10-22T23:11:52     @{ResponseTime=470}       Up             192.168.2.10
2014-10-22T23:11:51                               Down           192.168.2.80  
2014-10-22T23:11:52     @{ResponseTime=7}         Up             192.168.2.254

It doesn't matter which one, my preference is the second one

Could you please help me with this matter. Even if it is not possible tell me aswell.

Thank you, Chris

coachrules
  • 13
  • 2

3 Answers3

3

I'll chime in late, not because the other answer are wrong by any means, they are both functional, but more so because nobody has pointed out that you are recreating the wheel.

You test the connection, and specify an erroraction for it that silently continues leaving your variable null. Then you have to test to see if the variable has results, and treat it one way, or if it doesn't treat it another way. What you have just done is made your own Try/Catch scenario. If you actually use the error to stop you can use the built in Try/Catch. Consider this approach:

$servers = "www.google.com","localhost","www.amazon.com"
$collection = @()
foreach ($server in $servers)
{
    Try{    
        $testconnection = Test-Connection $server -Count 2 -ErrorAction Stop
        $testconnection | ForEach{$collection += New-Object PSObject -Property ([ordered]@{
            'TimeStamp' = Get-Date -Format s
            'Server' = $server
            'ResponseTime' = $_.responsetime
            'Results' = 'Up'})
        }
    }
    Catch{
        $collection += New-Object PSObject -Property ([ordered]@{
            'TimeStamp' = Get-Date -Format s
            'Server' = $server
            'ResponseTime' = $null
            'Results' = 'Unreachable'
        })
    }

}
$collection #| Export-Csv -Path ".\ServerStatus.csv" -NoTypeInformation

That tries to ping the server, and if it can it adds a custom object to the $collection array with the desired information. If the ping fails it also adds an object to the $collection showing that the server was unreachable.

Also, you had $collection = $(). I assume you were trying to create an empty array, which is correctly done $collection = @() (corrected in my suggested code). Now, I commented out the Export-CSV so I could see the results. This is what I saw:

TimeStamp                      Server                            ResponseTime Results
---------                      ------                            ------------ -------
2014-10-22T17:54:22            www.google.com                               9 Up
2014-10-22T17:54:22            www.google.com                              12 Up
2014-10-22T17:54:23            localhost                                    0 Up
2014-10-22T17:54:23            localhost                                    0 Up
2014-10-22T17:54:27            www.amazon.com                                 Unreachable

Amazon didn't let me ping it, so it shows as unreachable.

Moving on to why your desired results are not practical... What you describe shows you pinging your servers and getting results from them at non-consecutive times. To do that you would have to do -count 1, and loop through the ForEach loop twice, so it would ping server 1 for 1 result, then server 2 for 1 result, then server 3 for 1 result. Then it would go back and ping server 1 for a second result, then server 2 for a second result, and then server 3 for a second result. If you wanted to do that you could I suppose, and it should give you your desired results, you would have to do something like this:

$servers = "www.google.com","localhost","www.amazon.com"
$collection = @()
$count = 2
for($i=1;$i -le $count;$i++){
    ForEach($server in $servers){
        do stuff to ping servers as described above, except change -count to 1
    }
}
$collection | export-CSV '.\ServerStatus.csv' -notype

That will give you your desired results, but it is slower. If you have to run this against more than a few servers it will be noticeably slower. For just those three servers listed it made the entire process go from taking 3.7240945 seconds to taking 7.6104075 seconds (roughly double).

TheMadTechnician
  • 34,906
  • 3
  • 42
  • 56
  • wow cpt obvious to the rescue :) how have i not thought about this – Paul Oct 23 '14 at 01:20
  • Both are working fine. I found this script somewhere on the internet. And edited to my own preferences. I am not good in scripting. But thanks for the support – coachrules Oct 24 '14 at 12:17
1

Instead of

$response = ($testconnection | select ResponseTime)
if ($response)
{
    $status["Results"] = "Up"
    $status["Responsetime"] = $response
}

do

if($testconnection)
  {
    $testconnection | % {
    $status = @{"ServerName" = $server; "TimeStamp" = (Get-Date -f s); "Results" = "Up"; "Responsetime"= $_.responsetime}; 
    New-Object -TypeName PSObject -Property $status -OutVariable serverStatus;
    $collection += $serverStatus }
  }
else
  {
    $status = @{"ServerName" = $server; "TimeStamp" = (Get-Date -f s); "Results" = "Down"};
    New-Object -TypeName PSObject -Property $status -OutVariable serverStatus;
    $collection += $serverStatus 
  }

The problem is that $testconnection or in your case $response is an array if the count of Test-Connection is greater then 1, so you have to loop through it and add the single entries to your collection.

Also to get the Value instead of the gibberish you get you have to call the .responsetime property.

Paul
  • 5,524
  • 1
  • 22
  • 39
  • Paul, I don't know how (I am not good in scripting) but when i try your one. I get a double result even is the count 1. – coachrules Oct 24 '14 at 12:18
0

In hopes I didn't make it too complicated I present this solution

$servers = "10.50.10.100","8.8.8.8","169.254.54.1"

$servers | ForEach-Object{
    $server = $_
    $timeStamp = (Get-Date -f s)
    $testconnection = Test-Connection $server -Count 2 -ErrorAction 0
    If(!$testconnection){
            $props = @{
                Server = $server
                TimeStamp = $timeStamp
                ResponseTime = ""
                Results = "Down"
            }

            New-Object -TypeName PSObject -Property $props

    } Else {
        $testconnection | ForEach-Object{
            $_ | Select-Object @{l='Server';e={$server}},@{l='TimeStamp';e={$timeStamp}},@{l='ResponseTime';e={$_.ResponseTime}},@{l='Results';e={"Up"}}
        }
    }
} | Export-Csv -Path ".\ServerStatus.csv" -NoTypeInformation

So your logic is still here but as you can see some things have been changed. Paul was right, in that you needed to loop for each ResponseTime element you had. I also have done that but with a different approach that, if nothing else, will show you some of the Power in PowerShell. A break down of the code

  1. Pipe $servers into a ForEach-Object. ForEach in works fine however I wanted to skip the saving the variables and just output straight to Export-CSV which is why I changed it.
  2. So if you use Test-Connection on a server that does not exist or errors for some reason then you need to create an object to represent that. Using the desired properties, build a object with required values. This is output to the pipe instead of using a temporary variable.
  3. When a connection test is successful then we need to output a number or variables to match the number of returns.
  4. Continuing from #3 we use Select-Object to output the desired values. l stand for label and e for expression. Yes you could easily just use another $props variable. Just illustrating another option.
  5. Since we changed the ForEach in the first step we can just output straight to Export-CSV

Sample output

Server       TimeStamp           ResponseTime Results
------       ---------           ------------ -------
10.50.10.100 2014-10-22T20:22:01 0            Up     
10.50.10.100 2014-10-22T20:22:01 0            Up     
8.8.8.8      2014-10-22T20:22:02 43           Up     
8.8.8.8      2014-10-22T20:22:02 39           Up     
169.254.54.1 2014-10-22T20:22:03              Down   
Matt
  • 45,022
  • 8
  • 78
  • 119