Created
April 29, 2024 07:00
-
-
Save earthdiver/c0bff1946aa35b29fd142fc99589b559 to your computer and use it in GitHub Desktop.
An arping tool for Windows. ( Use the function inside on Powershell console. )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @Powershell -NoP -C "&([ScriptBlock]::Create((gc '%~f0'|?{$_.ReadCount -gt 1}|Out-String)))" %* & exit/b | |
| # by earthdiver1 | |
| [CmdletBinding(PositionalBinding=$False)] | |
| Param( | |
| [parameter(Position=0)][String]$Target, # IP address of the target host | |
| [String]$Source, # if you have multiple interfaces (optional, default value: 0 (all interfaces)) | |
| [Alias("n")][Int]$Count=4, # the number of ARP requests to send (optional, default value: 4) | |
| [Int]$Interval=1 # the interval between ARP requests, in seconds (optional, default value: 1) | |
| ) | |
| Function arping { | |
| [CmdletBinding(PositionalBinding=$False)] | |
| Param( | |
| [parameter(Position=0)][String]$Target, # IP address of the target host | |
| [String]$Source, # if you have multiple interfaces (optional, default value: 0 (all interfaces)) | |
| [Alias("n")][Int]$Count=4, # the number of ARP requests to send (optional, default value: 4) | |
| [Int]$Interval=1 # the interval between ARP requests, in seconds (optional, default value: 1) | |
| ) | |
| if (-not $Target) { | |
| Write-Output "Usage: arping <target IP address> [-Source <source IP address>]" | |
| Write-Output " [-Count/-n <number of ARP requests>] [-Interval <interval between ARP requests>]" | |
| exit | |
| } | |
| if ($Count -lt 1) { exit } | |
| $code = '[DllImport("iphlpapi.dll")]public static extern int SendARP(UInt32 DestIP,UInt32 SrcIP,byte[] pMacAddr,ref UInt32 PhyAddrLen);' | |
| $type = Add-Type -MemberDefinition $code -Name Win32SendARP -PassThru | |
| try { | |
| $DstIP = [UInt32][System.Net.IPAddress]::Parse($Target).Address | |
| } catch { | |
| Write-Output "Target IP address $Target is invalid. Please check it and try again." | |
| exit | |
| } | |
| if ($Source) { | |
| try { | |
| $SrcIP = [UInt32][System.Net.IPAddress]::Parse($Source).Address | |
| } catch { | |
| Write-Output "Source IP address $Source is invalid. Please check it and try again." | |
| exit | |
| } | |
| } else { | |
| $SrcIP = [UInt32]0 | |
| } | |
| $MacAddr = New-Object Byte[] 6 | |
| $n_sent = 0 | |
| $n_received = 0 | |
| $maxT = 0. | |
| $minT = 9999. | |
| $sumT = 0. | |
| Write-Output "" | |
| Write-Output "ARPING ${Target}:" | |
| for($i=1; $i -le $Count; $i++) { | |
| $n_sent++ | |
| $t = (Measure-Command { $result = $type::SendARP($DstIP, $SrcIP, $MacAddr, [ref][UInt32]$MacAddr.Length) }).TotalMilliseconds | |
| if ($result -eq 0) { # NO_ERROR | |
| $n_received++ | |
| if ($t -gt $maxT) { $maxT = $t } | |
| if ($t -lt $minT) { $minT = $t } | |
| $sumT += $t | |
| Write-Output "Reply from $(($MacAddr | %{ '{0:x2}' -F $_ }) -Join '-') (as $Target): index=$i, time=$(($t).ToString('0'))ms" | |
| } elseif ($result -eq 67) { # ERROR_BAD_NET_NAME | |
| Write-Output "Request timed out." | |
| } else { | |
| Write-Output "SendARP failed with error: $result" | |
| } | |
| if ($i -lt $Count) { Start-Sleep -Milliseconds ([Math]::Max(($Interval*1000 - [Int]$t), 0)) } | |
| } | |
| Write-Output "" | |
| Write-Output "Ping statistics for $Target/arp:" | |
| Write-Output " Packets: Sent=$n_sent, Received=$n_received, Lost=$($n_sent-$n_received) ($((($n_sent-$n_received)/$n_sent*100).ToString('0'))% loss)" | |
| if ($n_received -gt 0) { | |
| Write-Output "Approximate round trip times in milli-seconds:" | |
| Write-Output " Minimum = $(($minT).ToString('0'))ms, Maximum = $(($maxT).ToString('0'))ms, Average = $(($sumT/$n_received).ToString('0'))ms" | |
| } | |
| } | |
| # update $PSBoundParameters with default parameter values | |
| foreach ($p in $MyInvocation.MyCommand.ScriptBlock.Ast.ParamBlock.Parameters) { | |
| $key = $p.Name.VariablePath.UserPath | |
| if ($PSBoundParameters.ContainsKey($key)) { Continue } | |
| $value = (Get-Variable $key).Value | |
| if ($value) { $PSBoundParameters.Add($key, $value) } | |
| } | |
| arping @PSBoundParameters |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment