#Ping IPs and Export the Errors to CSV

16 messages · Page 1 of 1 (latest)

fiery leaf
#

I have been working on a script that will take a CSV of IP addresses and ping them. However, I’m hitting a road-block.

I would like to ping the IP address and have two outcomes:

1.) If ping is successful, do nothing.

2.) If ping is unsuccessful, add that IP address to a separate CSV which will be exported at the end of the script.

This would loop until we run out of IPs to ping on the list.

So far what I have below works for creating a loop and pinging the IPs from a CSV, but I’m unsure how to add in the two actions above.

Please don’t spell it out; give me a tip and let me run with it. This project has been fun and I feel like I’m so close to the answer!

$path = "C:\Temp\TestFolder\FolderName.csv"
$csv = Import-Csv -Path $path

foreach($line in $csv)
{
    $properties = $line | Get-Member -MemberType Properties
    for($i=0; $i -lt $properties.Count;$i++)
    {
        $column = $properties[$i]
        $columnvalue = $line | Select -ExpandProperty $column.Name

        #Write-Output $columnvalue #This line is unneeded. It simply tells the viewer which IP address we're on.
        $testconnection = Test-Connection -ComputerName $columnvalue
        $testconnection

        
    }
}
idle tree
#

Try something like this.

$csv = ConvertFrom-Csv @'
IP
192.168.1.1
192.168.1.2
192.168.1.3
'@

# loop through the list and test-connection.
$results = foreach ($line in $csv) {
    If (-Not (Test-Connection -ComputerName $line.ip -Quiet -TimeoutSeconds 2 -Count 1)) { 
        # ping unsuccessful.
        <insert code here>
    }
}
fiery leaf
#

I merged part of what you suggested and what I already had to create this:

$stopwatch = [System.Diagnostics.Stopwatch]::new()]
$stopwatch.Start()

$path = "C:\Temp\IPAddressTest.csv"
$csv = Import-Csv -path $path

$CSVFail = "C:\Temp\IPAddressFailure.csv"
New-Item C:\Temp\IPAddressFailure.csv -ItemType File

foreach ($line in $csv)
{
  $properties =$line | Get-Member -MemberType Properties
  For($i=0; $i -lt $properties.Count;$i++)
    {
      $column = $properties[$i]
      $columnvalue = $line | Select -ExpandProperty $column.Name

      If (-Not (Test-Connection -Delay 1 -Count 1 -ComputerName $columnvalue))
      {
        Write-Output "IP Address $($columnvalue) has failed. It will be written to the CSV."
        Add-Content -Path "C:\Temp\IPAddressFailure.CSV" -Value $columnvalue
      }
    }
}

It does everything that I want except when it writes the failed IP addresses to the CSV it goes down the first initial row of the CSV without overwriting the previous data. I would like it to start at the first row and overwrite the existing data, but that's something I'll fix for later.

Well, either that or having the date written at the top of the column and then it'll write the failed IP addresses starting at (Column Letter)2.

I'll tweak it later.

I really appreciate your help!

fiery leaf
#

JK!

I think something is wrong. Every IP address I ping, even 8.8.8.8 and 139.130.4.5, are dropping all of my packets.

Everything in this CSV is coming back with 100% packet loss 😦

sage kindle
#

what's the point of the Get-Member part?

#

it kind of looks like you just need ```ps
Import-Csv ... |
Where-Object { -not (Test-Connection $_.WhateverColumn -Count 1 -Quiet) }

I know you said not to give an answer, and so close... but it looks like it's meandered in a very complicated direction.
fiery leaf
mossy wharf
#

I feel like this would be a good candidate for threading depending on how many IPs you might be pining

fiery leaf
mossy wharf
#

this is shooting from the hip (I'm not at work to test this) but something like:

#
$ips = @(
        [PSCustomObject]@{'ip' = '127.0.0.1'}
        [PSCustomObject]@{'ip' = '10.0.1.1'}
    )

$notPingable = $ips | Foreach-Object -ThrottleLimit 5 -Parallel {
    if (-not (Test-Connection -TargetName $_.ip -Count 1 -Quiet -TimeoutSeconds 3)) {
      [PSCustomObject]@{  
         ip = $_.ip
      }
    }
}
#

this (if the syntax is right) would break the job up across 5 concurrent threads (much quicker) and not allow one unpingable IP hold up the whole job for a long time. In theory, $output would be an array of objects with the IPs that did not ping

fiery leaf
#

Update on the script:

I haven't dived deep enough into parallels to make that work, but the script has been optimized a bit further.

$path = "C:\Temp\IPAddressTest.csv"
$csv = Import-Csv -path $path

$results = foreach ($line in $csv)
{  
  If (-Not (Test-Connection -Delay 1 -Count 1 -ComputerName $line.expression))
  {
    $line.expression
  }
}
$results | Export-CSV -Path "C:\Temp\IPAddressFailure.csv" -NoTypeInformation
fading oar
#

don’t spell it out;
Some of the examples used foreach(x in y) {},
some used ForEach-Object{ x } so I wanted to expand on that

In loose terms, these terms are sort of interchangeable below: ScriptBlock, Command, function

One thing to notice between foreach( x in y ) vs ForEach-Object and Where-Object
is first is a language keyword, the rest are commands / functions.

Foreach-Object, and Where-Object are functions, which take a ScriptBlock as a parameter.
Once you know that, you can change how you use logic for control flow. (More in a second)

An easy way to remember is:

Does for x in y have the word in in it? or ; like for(x; y; c) ?
then it's the keyword. Otherwise it's the function

Here's some code to play with, first, foreach

$numbers = 0..10
$Numbers | ForEach-Object {
    $current = $_
    "iter: $Current"
    # note, this return will exit this function call
    # Foreach-Object calls this function once per every line
    # that means when it's -ge than 5, return doesn't  skip processing those records
    if( $Current -lt 5 ) {
        return
    }

    " => Process $Current"
}

Outputs
||```ps1
iter: 0
iter: 1
iter: 2
iter: 3
iter: 4
iter: 5
=> Process 5
iter: 6
=> Process 6
iter: 7
=> Process 7
iter: 8
=> Process 8
iter: 9
=> Process 9
iter: 10
=> Process 10

#

in the screenshot quoting chris's code, the red section is a ScriptBlock that's a parameter for the function where-object

It looks a lot like a where { } block, but it's not


(resuming from tangent )

Now lets compare how breaking a control block acts different

$numbers = 0..10
foreach($current in $numbers) {
   "iter:  $current"
    # note: everything after 5 is totally skipped
    if( $current -gt 5 ) {
        break
    }

    " ==> Do stuff with $current"
}

outputs
||```ps1
iter: 0
==> Do stuff with 0
iter: 1
==> Do stuff with 1
iter: 2
==> Do stuff with 2
iter: 3
==> Do stuff with 3
iter: 4
==> Do stuff with 4
iter: 5
==> Do stuff with 5
iter: 6

Now guess what this will run. it's almost identical code
```ps1
$numbers = 0..10
foreach($current in $numbers) { 
   "iter:  $current"

    if( $current -lt 5 ) { 
        break
    }

    " ==> Do stuff with $current"
}

Outputs
||```ps1
iter: 0

#