<# .SYNOPSIS Simple local network scanner using ping.exe. .DESCRIPTION - Detects your primary IPv4 address and subnet. - Pings every IP in that subnet using ping.exe. - Shows IP, optional hostname, and MAC address (from ARP cache). - Default timeout: 250 ms per host (adjustable). .PARAMETER TimeoutMs Ping timeout in milliseconds per host. Default: 250 ms. .PARAMETER ResolveNames If set, try to resolve hostnames via DNS / reverse lookup. .EXAMPLE .\Scan-Network.ps1 .EXAMPLE .\Scan-Network.ps1 -TimeoutMs 500 -ResolveNames -Verbose #> [CmdletBinding()] param( [int] $TimeoutMs = 250, [switch] $ResolveNames ) function ConvertTo-UInt32 { param( [Parameter(Mandatory = $true)] [System.Net.IPAddress] $IPAddress ) $bytes = $IPAddress.GetAddressBytes() [Array]::Reverse($bytes) return [BitConverter]::ToUInt32($bytes, 0) } function ConvertFrom-UInt32 { param( [Parameter(Mandatory = $true)] [uint32] $Value ) $bytes = [BitConverter]::GetBytes($Value) [Array]::Reverse($bytes) return [System.Net.IPAddress]::new($bytes) } Write-Host "Detecting local IPv4 configuration..." -ForegroundColor Cyan # Get a usable IPv4 address (skip loopback / APIPA) $ipConfig = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notlike '169.254*' -and $_.IPAddress -notlike '127.*' -and $_.PrefixOrigin -ne 'WellKnown' } | Sort-Object -Property SkipAsSource, InterfaceMetric | Select-Object -First 1 if (-not $ipConfig) { Write-Error "No valid IPv4 address found. Are you connected to a network?" exit 1 } $localIp = [System.Net.IPAddress]::Parse($ipConfig.IPAddress) $prefixLength = $ipConfig.PrefixLength Write-Host "Using local IP: $($localIp) /$prefixLength on interface: $($ipConfig.InterfaceAlias)" -ForegroundColor Green if ($prefixLength -lt 16) { Write-Warning "Subnet is large (/16 or bigger). This scan may take a while." } # Build subnet mask from prefix length $maskUint32 = if ($prefixLength -eq 0) { 0u } else { [uint32]::MaxValue -shl (32 - $prefixLength) } $ipUint32 = ConvertTo-UInt32 -IPAddress $localIp $networkUint32 = $ipUint32 -band $maskUint32 $broadcastUint32 = $networkUint32 -bor (-bnot $maskUint32) Write-Host "Calculated network range: $(ConvertFrom-UInt32 $networkUint32) - $(ConvertFrom-UInt32 $broadcastUint32)" -ForegroundColor Yellow # Build list of host IPs (skip network & broadcast) $start = $networkUint32 + 1 $end = $broadcastUint32 - 1 if ($end -lt $start) { Write-Error "Invalid IP range calculated. Aborting." exit 1 } $ipList = New-Object System.Collections.Generic.List[System.Net.IPAddress] for ($i = $start; $i -le $end; $i++) { $ipList.Add( (ConvertFrom-UInt32 -Value $i) ) } Write-Host "Scanning $($ipList.Count) addresses with timeout = ${TimeoutMs}ms using ping.exe ..." -ForegroundColor Cyan $results = @() $pingCmd = "$env:SystemRoot\System32\ping.exe" foreach ($ip in $ipList) { $ipString = $ip.ToString() Write-Verbose "Pinging $ipString ..." # Call ping.exe with separate arguments $null = & $pingCmd -n 1 -w $TimeoutMs $ipString $exitCode = $LASTEXITCODE if ($exitCode -eq 0) { Write-Host "Host up: $ipString" -ForegroundColor DarkGreen $hostname = $null if ($ResolveNames) { try { $entry = [System.Net.Dns]::GetHostEntry($ipString) $hostname = $entry.HostName } catch { $hostname = $null } } # Query ARP cache for MAC address $mac = $null try { $arpOutput = arp -a $ipString 2>$null if ($arpOutput) { $line = $arpOutput -split "`n" | Where-Object { $_ -match $ipString } | Select-Object -First 1 if ($line -and ($line -match '([0-9a-fA-F]{2}-){5}[0-9a-fA-F]{2}')) { $mac = $Matches[0] } } } catch { $mac = $null } $results += [PSCustomObject]@{ IPAddress = $ipString Hostname = $hostname MAC = $mac } } else { Write-Verbose "No reply from $ipString (exit code $exitCode)" } } Write-Host "" Write-Host "Scan complete. Devices that responded to ping.exe:" -ForegroundColor Green if ($results.Count -eq 0) { Write-Host "No active hosts found (no ping replies)." -ForegroundColor Yellow } else { $results | Sort-Object IPAddress | Format-Table -AutoSize } # Uncomment below line if you want to export to CSV automatically: # $results | Sort-Object IPAddress | Export-Csv -Path ".\NetworkScan_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" -NoTypeInformation