# ========================= # HYBRID ARP + ICMP SCANNER # CSV EXPORT (Downloads/Desktop) # ========================= function Test-DeviceIcmp { param([string]$Ip) try { ((New-Object System.Net.NetworkInformation.Ping).Send($Ip,1000).Status -eq "Success") } catch { $false } } function Get-MacAddressHybrid { param([string]$Ip) if (-not ("Win32.Arp" -as [type])) { Add-Type -Language CSharp -TypeDefinition @" using System; using System.Net; using System.Runtime.InteropServices; namespace Win32 { public static class Arp { [DllImport("iphlpapi.dll", ExactSpelling=true)] public static extern int SendARP(uint DestIP, uint SrcIP, byte[] pMacAddr, ref int PhyAddrLen); public static string GetMac(string ip) { IPAddress dst = IPAddress.Parse(ip); byte[] macAddr = new byte[6]; int len = macAddr.Length; byte[] ipBytes = dst.GetAddressBytes(); uint destIp = (uint)(ipBytes[0] | (ipBytes[1] << 8) | (ipBytes[2] << 16) | (ipBytes[3] << 24)); int result = SendARP(destIp, 0, macAddr, ref len); if (result != 0 || len <= 0) return null; return BitConverter.ToString(macAddr, 0, len); } } } "@ } try { $mac = [Win32.Arp]::GetMac($Ip) if ([string]::IsNullOrWhiteSpace($mac)) { $null } else { $mac } } catch { $null } } # ------------------------- # STORE NUMBER (4 DIGITS) # ------------------------- do { $storeDigits = (Read-Host "Enter 4-digit store number").Trim() } until ($storeDigits -match '^\d{4}$') $storeTag = "STP$storeDigits" # ------------------------- # BASE IP INPUT # ------------------------- $baseIpInput = (Read-Host "Enter BASE IP (example: 192.168.0)").Trim().TrimEnd('.') $octets = $baseIpInput.Split('.') if ($octets.Count -ne 3) { Write-Host "Invalid BASE IP format." -ForegroundColor Red exit 1 } [int]$o1 = $octets[0] [int]$o2 = $octets[1] [int]$o3 = $octets[2] # ------------------------- # SCAN SETTINGS # ------------------------- $startHost = 1 $endHost = 250 $subnetCount = 4 # base + next 3 $subnetStep = 1 # ------------------------- # RUNSPACE POOL # ------------------------- $pool = [runspacefactory]::CreateRunspacePool(1, [Environment]::ProcessorCount) $pool.Open() $jobs = @() # ------------------------- # QUEUE SCANS # ------------------------- for ($s = 0; $s -lt $subnetCount; $s++) { $third = $o3 + ($s * $subnetStep) if ($third -gt 255) { break } Write-Host "`n--- Scanning $o1.$o2.$third.X ---" -ForegroundColor Cyan $prefix = "$o1.$o2.$third." foreach ($h in $startHost..$endHost) { $ip = "$prefix$h" $ps = [powershell]::Create().AddScript({ param($ip) function Test-DeviceIcmp { param([string]$Ip) try { ((New-Object System.Net.NetworkInformation.Ping).Send($Ip,1000).Status -eq "Success") } catch { $false } } function Get-MacAddressHybrid { param([string]$Ip) try { [Win32.Arp]::GetMac($Ip) } catch { $null } } $mac = Get-MacAddressHybrid $ip if ($mac) { return [PSCustomObject]@{ IP=$ip; MAC=$mac; Method="ARP"; Online=$true } } if (Test-DeviceIcmp $ip) { $mac2 = Get-MacAddressHybrid $ip return [PSCustomObject]@{ IP=$ip MAC=$(if ($mac2) { $mac2 } else { "MAC not found" }) Method="ICMP" Online=$true } } [PSCustomObject]@{ IP=$ip; MAC=""; Method="NONE"; Online=$false } }).AddArgument($ip) $ps.RunspacePool = $pool $jobs += [PSCustomObject]@{ Pipe=$ps; Handle=$ps.BeginInvoke() } } } # ------------------------- # COLLECT RESULTS # ------------------------- $results = @() foreach ($job in $jobs) { $res = $job.Pipe.EndInvoke($job.Handle) $job.Pipe.Dispose() if ($res.Online) { Write-Host "$($res.IP) - SUCCESS ($($res.Method))" $results += [PSCustomObject]@{ Store = $storeTag IP = $res.IP MAC = $res.MAC Method = $res.Method ScanTime = (Get-Date) } } } $pool.Close() # ------------------------- # CSV EXPORT LOCATION # ------------------------- $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $filename = "${storeTag}_ScanReport_${timestamp}.csv" $downloads = Join-Path $env:USERPROFILE "Downloads" $desktop = Join-Path $env:USERPROFILE "Desktop" if (Test-Path $downloads) { $exportPath = Join-Path $downloads $filename } else { $exportPath = Join-Path $desktop $filename } $results | Export-Csv -Path $exportPath -NoTypeInformation -Encoding UTF8 Write-Host "`nScan complete." -ForegroundColor Green Write-Host "CSV saved to:" -ForegroundColor Yellow Write-Host $exportPath -ForegroundColor Cyan