Jump to page sections
Here goes my fairly polished attempt at a PowerShell nmap-like program that port scans subnets using CIDR notation or a pre-generated list of IP addresses or computer names. It uses efficient runspaces for concurrency (but Linux nmap should be way faster - sad face). This script should definitely replace this old port scan script that I wrote in a former life, eons ago. It also uses PSipcalc under the hood. It has now been published to the PowerShell gallery (see the download section) and feedback is welcome there or on GitHub, where it also currently resides. It has been out in the wild for a couple of years now and not much feedback has been produced. It seems people are pretty happy with it?

When you run it, it will first perform a ping sweep of the specified hosts/IPs/networks - without giving any feedback - the progress bar comes when DNS lookups and port scans begin. Only alive hosts will be port scanned, unless you specify the parameter -ScanOnPingFail, which will make it scan the port(s) on all hosts regardless of ping status.

You can use the -Verbose parameter - to have your screen flooded with activity most of the time. This program is not perfect for runs against single hosts. There is some overhead to support faster execution against '''many''' hosts. But really it's just a matter of 3.5 seconds of sleep time plus otherwise minimal overhead, even with a single host. Still seems faster than Test-Port (albeit with different functionality)

To just check for an open port on a single host, you can use something like the code below. This also has the added bonus of using an asynchronous call with a specified timeout in milliseconds ("3000" here).

#$computer, $port = $args[0,1] # assign values to these
$mysock = new-object net.sockets.tcpclient
$IAsyncResult = [IAsyncResult] $mysock.BeginConnect($computer, $port, $null, $null)
measure-command { $succ = $iasyncresult.AsyncWaitHandle.WaitOne(3000, $true) } | % totalseconds

I'm adding that the real Linux utility nmap's ping sweep fails to detect most of my Windows hosts on my home LAN, and only finds 11 "alive" hosts, whereas my PSnmap seemingly finds 21, including many more Windows hosts. In my limited experience with port scanning, I've found that results can vary slightly from time to time, and from host to host you scan from, and depending on the utility you use. I've already seen some discrepancies between nmap and my script.

Superficially tested with PowerShell versions 2, 3, 4 and 5.

Screenshot examples of PSnmap

Here's me scanning and some hosts specified again with names to check reverse DNS functionality, and filtering out only those that respond to ping, meaning they were scanned (also without the -ScanOnPingFail parameter).

We can see how 639 (382 port/DNS + 257 pings) port scans, pings and DNS lookups are finished in 27 seconds.

Download PSnmap

*PSnmap.zip - v1.2 as of 2017-06-08. PSnmap packaged as a module together with PSipcalc. Exports Invoke-PSipcalc (alias PSipcalc) and Invoke-PSnmap (alias PSnmap).

Earlier versions:

Old non-modularized versions of required script files:

PSnmap is also on GitHub. https://github.com/EliteLoser/PSnmap - there's a newer version there at this time of writing. That one has also been published to the PowerShell Gallery. As of 2018-07-24 it's version 1.3.1.

If you have Windows Management Framework 5 or higher (WMF 5 is available for Windows 7 and up), you can install my PSnmap module from the PowerShell gallery, a Microsoft project and online repository for scripts.

PSnmap works well with PowerShell Core, currently the latest version is PowerShell 7, on Linux as well.

To install with WMF 5 and up (to get the latest PSnmap module version available), you can simply run this command (requires an internet connection):
Install-Module -Name PSnmap #-Scope CurrentUser #-Force

Parameters for PSnmap

The (right kind of) lazy way to document here:
    # CIDR, IP/subnet, IP, or DNS/NetBIOS name.
    [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string[]] $ComputerName,

    # Port or ports to check.
    [int[]] $Port,

    # Perform a DNS lookup.
    [switch] $Dns,

    # Scan all hosts even if ping fails.
    [switch] $ScanOnPingFail,

    # Number of concurrent threads.
    [int] $ThrottleLimit = 32,

    # Do not display progress with Write-Progress.
    [switch] $HideProgress,

    # Timeout in seconds. Causes problems if too short. 30 as a default seems OK.
    [int] $Timeout = 30,

    # Port connect timeout in milliseconds. 5000 as a default seems sane.
    [int] $PortConnectTimeoutMs = 5000,

    # Do not display the end summary with start and end time, using Write-Host.
    [switch] $NoSummary

    # Add service name as collected from IANA to the port number property name.
    [Switch] $AddService
Powershell      Windows      Networking          All Categories

Google custom search of this website only

Minimum cookies is the standard setting. This website uses Google Analytics and Google Ads, and these products may set cookies. By continuing to use this website, you accept this.

If you want to reward my efforts