Power Shell test-connection and then get computers name or mac-addr

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

Answers (3)

YetAnotherRandomUser
YetAnotherRandomUser

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

Source

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

Source

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

ravikanth
ravikanth

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

Austin T French
Austin T French

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:

  • .NET is at your disposal, not just native cmdlets and Windows Commands
  • Do use built in operators like $?

Upvotes: 3

Related Questions