Reputation: 93
So I have written a simple pinger that ping all that a network. I'm using test-connection, but I what to also get the devises name as well.
So I'm using cmd's nbtstat to get the name but (lets say it's not clean)
Is there a way to do this a bit cleaner?
this is what i have got
$a = New-Object System.Collections.ArrayList
for ($i =0;$i -le 225; $i++){
if (Test-Connection 192.168.1.$i -Count 1 -Quiet){
echo "live 192.168.1.$i"
$a.add("192.168.1.$i")
}else {
echo "dead 192.168.1.$i"
}
}
echo $a
foreach ($i in $a){
Test-Connection $i -Count 1
}
foreach ($i in $a){
nbtstat -a $i
}
Upvotes: 1
Views: 10954
Reputation: 1408
Test-Connection
and Test-NetConnection
now support returning more information, including names. The latter requires Power Shell 5.
Test-Connection
EXAMPLES
Example 1: Send echo requests to a remote computer
PS C:\> Test-Connection "Server01"
Source Destination IPV4Address IPV6Address Bytes Time(ms)
------ ----------- ----------- ----------- ----- --------
ADMIN1 Server01 10.59.137.44 32 0
ADMIN1 Server01 10.59.137.44 32 0
ADMIN1 Server01 10.59.137.44 32 0
ADMIN1 Server01 10.59.137.44 32 1
Test-NetConnection
Test ping connectivity with detailed results
PS C:\> Test-NetConnection -InformationLevel "Detailed"
ComputerName : internetbeacon.msedge.net
RemoteAddress : 2a01:111:2003::52
NameResolutionResults : 2a01:111:2003::52
13.107.4.52
InterfaceAlias : Ethernet
SourceAddress : 2001:4898:d8:33:81e8:7b49:8bf5:8710
NetRoute (NextHop) : fe80::200:5eff:fe00:203
PingSucceeded : True
PingReplyDetails (RTT) : 6 ms
Also, you mention that you are pinging a whole network. That's how found your question (among others), because I was trying to do a ping sweep too. I settles on this script. The guy calls it Fast Ping Sweep Asynchronous.
Even being a Power Shell n00b, I was able to pipe its output, and then modify its output to only include what I wanted. I came across other scripts, but could not decipher their scripts to modify them for my purposes.
I'm not sure what version Power Shell this requires, but it works on v4 and v5.
I have seen most of the Powershell IP scanner, ping sweeping scripts but none of them uses the PingASync method.The "problem" with synchronous scripts is that they have to wait until a node replies or times out before continuing to the next address.Using this approach may take s
function Global:Ping-IPRange {
<#
.SYNOPSIS
Sends ICMP echo request packets to a range of IPv4 addresses between two given addresses.
.DESCRIPTION
This function lets you sends ICMP echo request packets ("pings") to
a range of IPv4 addresses using an asynchronous method.
Therefore this technique is very fast but comes with a warning.
Ping sweeping a large subnet or network with many swithes may result in
a peak of broadcast traffic.
Use the -Interval parameter to adjust the time between each ping request.
For example, an interval of 60 milliseconds is suitable for wireless networks.
The RawOutput parameter switches the output to an unformated
[System.Net.NetworkInformation.PingReply[]].
.INPUTS
None
You cannot pipe input to this funcion.
.OUTPUTS
The function only returns output from successful pings.
Type: System.Net.NetworkInformation.PingReply
The RawOutput parameter switches the output to an unformated
[System.Net.NetworkInformation.PingReply[]].
.NOTES
Author : G.A.F.F. Jakobs
Created : August 30, 2014
Version : 6
.EXAMPLE
Ping-IPRange -StartAddress 192.168.1.1 -EndAddress 192.168.1.254 -Interval 20
IPAddress Bytes Ttl ResponseTime
--------- ----- --- ------------
192.168.1.41 32 64 371
192.168.1.57 32 128 0
192.168.1.64 32 128 1
192.168.1.63 32 64 88
192.168.1.254 32 64 0
In this example all the ip addresses between 192.168.1.1 and 192.168.1.254 are pinged using
a 20 millisecond interval between each request.
All the addresses that reply the ping request are listed.
.LINK
http://gallery.technet.microsoft.com/Fast-asynchronous-ping-IP-d0a5cf0e
#>
[CmdletBinding(ConfirmImpact='Low')]
Param(
[parameter(Mandatory = $true, Position = 0)]
[System.Net.IPAddress]$StartAddress,
[parameter(Mandatory = $true, Position = 1)]
[System.Net.IPAddress]$EndAddress,
[int]$Interval = 30,
[Switch]$RawOutput = $false
)
$timeout = 2000
function New-Range ($start, $end) {
[byte[]]$BySt = $start.GetAddressBytes()
[Array]::Reverse($BySt)
[byte[]]$ByEn = $end.GetAddressBytes()
[Array]::Reverse($ByEn)
$i1 = [System.BitConverter]::ToUInt32($BySt,0)
$i2 = [System.BitConverter]::ToUInt32($ByEn,0)
for($x = $i1;$x -le $i2;$x++){
$ip = ([System.Net.IPAddress]$x).GetAddressBytes()
[Array]::Reverse($ip)
[System.Net.IPAddress]::Parse($($ip -join '.'))
}
}
$IPrange = New-Range $StartAddress $EndAddress
$IpTotal = $IPrange.Count
Get-Event -SourceIdentifier "ID-Ping*" | Remove-Event
Get-EventSubscriber -SourceIdentifier "ID-Ping*" | Unregister-Event
$IPrange | foreach{
[string]$VarName = "Ping_" + $_.Address
New-Variable -Name $VarName -Value (New-Object System.Net.NetworkInformation.Ping)
Register-ObjectEvent -InputObject (Get-Variable $VarName -ValueOnly) -EventName PingCompleted -SourceIdentifier "ID-$VarName"
(Get-Variable $VarName -ValueOnly).SendAsync($_,$timeout,$VarName)
Remove-Variable $VarName
try{
$pending = (Get-Event -SourceIdentifier "ID-Ping*").Count
}catch [System.InvalidOperationException]{}
$index = [array]::indexof($IPrange,$_)
Write-Progress -Activity "Sending ping to" -Id 1 -status $_.IPAddressToString -PercentComplete (($index / $IpTotal) * 100)
Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($index - $pending) -PercentComplete (($index - $pending)/$IpTotal * 100)
Start-Sleep -Milliseconds $Interval
}
Write-Progress -Activity "Done sending ping requests" -Id 1 -Status 'Waiting' -PercentComplete 100
While($pending -lt $IpTotal){
Wait-Event -SourceIdentifier "ID-Ping*" | Out-Null
Start-Sleep -Milliseconds 10
$pending = (Get-Event -SourceIdentifier "ID-Ping*").Count
Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($IpTotal - $pending) -PercentComplete (($IpTotal - $pending)/$IpTotal * 100)
}
if($RawOutput){
$Reply = Get-Event -SourceIdentifier "ID-Ping*" | ForEach {
If($_.SourceEventArgs.Reply.Status -eq "Success"){
$_.SourceEventArgs.Reply
}
Unregister-Event $_.SourceIdentifier
Remove-Event $_.SourceIdentifier
}
}else{
$Reply = Get-Event -SourceIdentifier "ID-Ping*" | ForEach {
If($_.SourceEventArgs.Reply.Status -eq "Success"){
$_.SourceEventArgs.Reply | select @{
Name="IPAddress" ; Expression={$_.Address}},
@{Name="Bytes" ; Expression={$_.Buffer.Length}},
@{Name="Ttl" ; Expression={$_.Options.Ttl}},
@{Name="ResponseTime"; Expression={$_.RoundtripTime}}
}
Unregister-Event $_.SourceIdentifier
Remove-Event $_.SourceIdentifier
}
}
if($Reply -eq $Null){
Write-Verbose "Ping-IPrange : No ip address responded" -Verbose
}
return $Reply
}
Upvotes: 1
Reputation: 25810
I'd do it a bit differently. Every time you contact a host, an ARP entry is created. Why not leverage that?
Get-WmiObject Win32_PingStatus -Filter "Address='192.168.1.2' AND ResolveAddressNames='true'" |
Select IPV4Address, ProtocolAddressResolved, @{
Name="PhysicalAddress";Expression={
([regex]::Matches($(arp -a $_.IPV4Address),"[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}",@('MultiLine', 'Ignorecase'))).value
}
}
Upvotes: 3
Reputation: 5131
There are always many ways to do something, one such example:
$Pinger = New-Object system.Net.NetworkInformation.Ping
$PC = "192.168.1.$i"
try{
$ErrorActionPreference = "Stop"
$PingResult = $Pinger.send($PC)
$ResultAddress = $PingResult.Address
$PingStatus = $PingResult.Status
$DNSObject = [System.Net.Dns]::GetHostEntry($PC).HostName
}
catch
{
}
finally
{
Write-Host "$PC $PingStatus $PingHost $? $DNSObject"
}
This gives more than you requested, but also I think it might also give you some ideas:
Upvotes: 3