Port Scanning with PowerShell
When a target has no nmap and uploading a scanner is noisy or blocked, PowerShell plus raw .NET sockets is the living-off-the-land fallback for network service discovery (MITRE T1046). The technique needs nothing beyond the CLR: System.Net.Sockets.TcpClient attempts a TCP connect to each host:port pair; a completed connection means the port is open.
The basic pattern
$ports = @(21, 22, 23, 53, 80, 88, 135, 139, 389, 443, 445, 636,
1433, 1521, 3306, 3389, 5985, 5986, 8080, 8443)
foreach ($port in $ports) {
$client = New-Object System.Net.Sockets.TcpClient
$connect = $client.BeginConnect($target, $port, $null, $null)
# Async connect + short wait: without a timeout, each closed port
# stalls the loop on the OS TCP connect timeout (~21 s on Windows)
$wait = $connect.AsyncWaitHandle.WaitOne(200, $false)
if ($client.Connected) { Write-Output "[+] $port open" }
$client.Close()
}Two implementation details matter more than the loop itself:
- Timeout discipline. A synchronous
Connect()on a filtered port blocks for the full OS retransmit budget (~21 seconds on Windows), which makes scanning more than a handful of ports impractical. UseBeginConnect+AsyncWaitHandle.WaitOne(ms)— orTest-NetConnection -Portper target — so filtered ports cost milliseconds, not seconds. - Where you scan from. The scan inherits the network position and identity of the host it runs on. That is the point: post-compromise, scanning from an internal host reaches segments perimeter tools can’t, and blends into admin traffic.
Test-NetConnection -ComputerName $target -Port $port is the built-in single-probe alternative — cleaner output, but serial and slower per call, so roll your own socket loop for anything beyond spot checks.
Trade-offs vs. a real scanner
| PowerShell sockets | nmap | |
|---|---|---|
| Prerequisites | None (CLR ships with Windows) | Binary upload or install |
| Speed | Serial unless you add runspaces/jobs | Engineered for parallelism |
| Detection signature | Long-lived process fanning out TCP connects | Classic scan patterns IDS know well |
| Stealth | Looks like an admin script — until it touches 500 hosts | Instantly recognizable |
The detectability cuts both ways: a PowerShell process opening TCP connections to hundreds of internal hosts/ports in seconds is one of the highest-signal Sysmon EID 3 (network connection) analytics a SOC can write. Script Block Logging (EID 4104) will also capture the scan source verbatim if it runs as a script.
Related
- bash-port-scanning — the UNIX-side equivalent using Bash’s
/dev/tcppseudo-device - netstat — the complementary view: which ports the local host itself is listening on, and which processes own them
- netsh-windows-firewall — the firewall context that decides which discovered ports are actually reachable
- invoke-webrequest-download-cradles — the other common pure-PowerShell network pattern (HTTP egress instead of TCP probing)