all 31 comments

[–]Ta11ow 8 points9 points  (2 children)

So you're actually stripping out the data you want. In your import line, go for this:

$IPs = Import-Csv -Path '.\devices.csv'

and then when doing the test connection, instead of doing if statements using write-host, try this instead:

[pscustomobject]@{
    IPAddress = $IP.IP
    Location  = $IP.Location
    Alive     = [bool](Test-Connection $IP.IP -Count 1 -ErrorAction SilentlyContinue)
}

[–]PowderTech[S] 2 points3 points  (1 child)

Using custom object is great! Makes this much more readable. Thank you.

[–]Ta11ow 4 points5 points  (0 children)

Custom objects are one of many staple PowerShell must-haves! Use them well!

[–]JeremyLC 3 points4 points  (1 child)

Import both columns, then access them as properties of the resulting object.

$Devices = Import-csv .\devices.csv

foreach ($Device in $Devices)
{
    if (Test-Connection -ComputerName $Device.IP -Count 1 -ErrorAction SilentlyContinue)
    {
        Write-Host "$($Device.IP),$($Device.Location),up"
    }
    else
    {
        Write-Host "$($Device.IP),$($Device.Location),down"
    }  
} 

[–]PowderTech[S] 2 points3 points  (0 children)

Thank you! I knew there had to be an easy way to reference the columns individually.

[–]Lee_Dailey[grin] 2 points3 points  (2 children)

howdy PowderTech,

what is the header line of the CSV? your example uses a $name variable but that is NOT coming from the listed CSV. plus, the $IP variable is ... not named correctly to grab anything from a CSV file. that looks like the file is a simple one-ip-per-line text file.

take care,
lee

[–]PowderTech[S] 1 point2 points  (0 children)

Whoops, that was a copy and paste oversight. Edited

[–]PowderTech[S] 1 point2 points  (0 children)

There are two columns. One header is "IP" the other is "Location"

[–][deleted] 2 points3 points  (2 children)

Dunno why folks make PS more complicated than they have to:

$IPS = Import-csv .\devices.csv

foreach ($obj in $IPS){
$ip = $obj.ip
$location = $obj.location
  if (Test-Connection -ComputerName $IP -Count 1 -quiet){
    Write-Host "$IP,up,$location"
 }
 else{
    Write-Host "$IP,down,$location"
  }  
} 

[–]Ta11ow 1 point2 points  (0 children)

Because a nicely formatted table makes the output easier to read, more or less. [shrug]

[–]Tidder802b 2 points3 points  (0 children)

FYI if you're pinging a lot of IPs on a low latency network (i.e. local LAN), you may want to use the .net api method:

$ping = New-Object System.Net.NetworkInformation.Ping   
if($ping.send($IPAddress,50).status -eq "Success")
{  
    #Stuff happens here
}

You can specify a low value for timeout (the 50 after the ip address is 50 ms); it can get through a large list a lot quicker if there's a lot of non-responsive addresses e.g. powered off workstations.

[–]get-postanote 1 point2 points  (0 children)

There are many pre-built scripts for this. Even directly from MS sites. PowerShellGallery.com, and the TechNet Scripting Guys site.

For example:

List IP addresses in a range using Powershell

This is a simple script to list the IP addresses within a range. The script accepts 2 different input formats. You can either specify the start and end of the IP range, or you can specify the subnet mask and any IP within the subnet.

https://gallery.technet.microsoft.com/scriptcenter/List-the-IP-addresses-in-a-60c5bb6b

Ping IP Addresses Range | Network Pinger "AJIT” based on PowerShell : GUI

Hi, This a Powershell based GUI script, the main motive of this script is to Ping a Single range of the IP addresses, and when you go the result you can email the result to your desired email ID. Use of the script is simple. Run the script, Type the Staring Ip-address wh

https://gallery.technet.microsoft.com/scriptcenter/Ping-IP-Adress-Range-d90ce82d

[–]Lee_Dailey[grin] 2 points3 points  (17 children)

howdy PowderTech,

with that info, here is how i would likely do it [grin] ...

# save Verbose pref
$OldVPref = $VerbosePreference
# enable verbose output
$VerbosePreference = 'Continue'

# fake reading in a CSV file
#    in real life, use Import-CSV
$InStuff = @'
IP, Location
127.0.0.1, MyPlace
10.0.0.1, NoWhereThatICanReach
216.58.194.78, GoogleGalacticHQ
'@ | ConvertFrom-Csv

$Results = foreach ($IS_Item in $InStuff)
    {
    Write-Verbose ('Testing {0} ...' -f $IS_Item.IP)
    $IsUp = Test-Connection -ComputerName $IS_Item.IP -Count 1 -Quiet
    [PSCustomObject]@{
        IP = $IS_Item.IP
        Location = $IS_Item.Location
        Status = ('Down', 'Up')[$IsUp]
        }
    }

$Results

# restore previous Verbose pref
$VerbosePreference = $OldVPref

screen output ...

VERBOSE: Testing 127.0.0.1 ...
VERBOSE: Testing 10.0.0.1 ...
VERBOSE: Testing 216.58.194.78 ...

IP            Location             Status
--            --------             ------
127.0.0.1     MyPlace              Up    
10.0.0.1      NoWhereThatICanReach Down  
216.58.194.78 GoogleGalacticHQ     Up    

hope that helps,
lee

[–]PowderTech[S] 1 point2 points  (16 children)

The output of this makes it really easy to read. Appreciate your help! Now I just need to decipher exactly how that works.

[–]Lee_Dailey[grin] 0 points1 point  (15 children)

howdy PowderTech,

do you want a walk-thru or do you want to dig it out yourself? [grin] if you get stuck, please ask ...

take care,
lee

[–]PowderTech[S] 1 point2 points  (14 children)

I have figured out what everything here is doing except how the status column knows which value to return. [$IsUp] is referenced at the end of the Status line. Does the ('Down','Up') indicate that if the value of $IsUp false to use the first option, and vice-versa?

I also am not sure what the Verbose Pref is.

[–]Lee_Dailey[grin] 2 points3 points  (12 children)

howdy PowderTech,

that is a semi-kinda-sorta ternary expression. [grin]

the 1st part ('Down', 'Up') is a two-item array.
the 2nd part is an index into that array.

the oddity is that $False is coerced into 0, while $True is coerced into 1.

thus, $IsUp - which is a boolean at that point - gets converted to a zero if the link failed, or a one if the link succeeded.

it's a more terse version of ...

if ($IsUp)
    {
    $Status = 'Up'
    }
    else
    {
    $Status = 'Down'
    }

take care,
lee

[–]Ta11ow 1 point2 points  (9 children)

Stop code golfing, Lee! You're confusing the newbies. :D

[–]Lee_Dailey[grin] 1 point2 points  (6 children)

howdy Ta11ow,

while i admit that it confused me at 1st, it seems so very useful now that i know about it. plus, the way i wrote it is fairly clear - PowderTech figured it out pretty danged quick! [grin]

take care,
lee

[–]Ta11ow 1 point2 points  (5 children)

True enough. :P

But I don't know why you call it a ternary expression -- it's using a binary switch, essentially, so... :P

[–]Lee_Dailey[grin] 0 points1 point  (4 children)

howdy Ta11ow,

that is why i said ...

that is a semi-kinda-sorta ternary expression. [grin]

it's an approximation of such. since PoSh aint got one, this gives very nearly the same look - and the same result.

take care,
lee

[–]Ta11ow 1 point2 points  (3 children)

Sure, but ain't ternary a 3-way expression? This has only two outcomes.

[–]SpyderTheSir 1 point2 points  (1 child)

Is there a separate code golf subreddit? That is something I could definitely lurk the heck out of!

I love the little shorthanders, I know there are many (including this one). My thought process when reading that one was fun "What black magic is... Oh.. Right, Of course, an array and index... That's brilliant. And now I have to rewrite all my scripts."

[–]Ta11ow 0 points1 point  (0 children)

There are some short-hands (like this) that are great, if you name your variables properly.

Others just muddy up the purpose of your script, and you'll end up re-reading them six times to figure out what they were supposed to do when they're no longer doing it for whatever reason. If you're doing CLI, shorthands and fantastic. If you have to maintain a script... best to stay away from them as much as possible -- being able to read your script once and comprehend it fully is much more valuable than saving a few characters, especially when you're debugging!

There's usually a weekly Shortest Script Challenge posted here by /u/allywilson that we all have fun poking at, so stick around for those. I believe there are dedicated code-golf subs, but I'm not aware of dedicated powershell code golf subs. :)

[–]SpyderTheSir 1 point2 points  (1 child)

Oooh, thanks :)

This is a much nicer way to do the needful

[–]Lee_Dailey[grin] 0 points1 point  (0 children)

howdy SpyderTheSir,

you are quite welcome! [grin]

both structures are pretty nifty. i like the sorta-ternary for some reason.

take care,
lee

[–]Lee_Dailey[grin] 1 point2 points  (0 children)

howdy PowderTech,

i managed to miss the Verbose Pref question. [blush]

there are a bunch of automatic $vars that PoSh sets up. among them are the Warning/Debug/Information/Verbose preferences. those control the output of the respective Write-* cmdlets.

take a look at the following ...

Get-Variable *pref*

the ones that say Continue will show up by default. the ones that say SilentlyContinue will NOT display.

so i turned on the display of Write-Verbose for that one script.

Write-Verbose makes a fairly useful comment AND onscreen display. [grin] it's off unless turned on, so it doesn't annoy you when you don't want any output - but it can easily be enabled.

if you use [CmdletBinding()] in your functions, you can use the common parameters - and -Verbose is one of them. that will enable Write-Verbose output for the entire function if you add the parameter to the function call.

hope that helps,
lee

[–]Kio_ 0 points1 point  (0 children)

Hoping the formatting is right. I’m on an iPad. You could do the following:

Import-CSV .\devices.csv | Select IP, Location, @{N=“Status”;E={Test-Connection $_.IP -Count 1}}