A few years ago I updated a PowerShell script I came across to scan a computer for open ports. My initial revision was aimed at making it more pipeline friendly in PowerShell v1.0. I recently needed to use the function for a project and realized it could benefit from a 2.0 upgrade.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
The new function uses a valid verb in the name, "Test", as opposed to the old "Scan". I was also able to take advantage of cmdletbinding, New-Object and Try/Catch. Not to mention comment based help, which is in the download file.
[cc lang="PowerShell"]
Function Test-Port {
[cmdletbinding(SupportsShouldProcess=$True,ConfirmImpact="Low")]
Param(
[Parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateNotNullorEmpty()]
[string[]]$Computername=$env:computername,
[array]$Ports=@("21","22","23","25","80","443","3389")
)
Begin {
#set values for Write-Progress
Write-Verbose "$(Get-Date) Starting $($myinvocation.mycommand)"
Write-Verbose "$(Get-Date) Scannning for ports $($ports -as [string])"
$activity="Port Scan"
}
Process {
Foreach ($computer in $computername) {
#whatif
if ($pscmdlet.ShouldProcess($($computer.ToUpper()))) {
$status="Scanning $computer"
Write-Verbose "$(Get-Date) $status"
$i=0
foreach ($port in $ports) {
$i++
Write-Progress -Activity $activity -status $status `
-currentoperation "port $port" -percentcomplete (($i/$ports.count)*100)
Try {
#create the TCPClient object
$tcp=New-Object System.Net.Sockets.TcpClient($computer, $port) -ErrorAction Stop
}
Catch {
Write-Verbose "$(Get-Date) Connection refused"
}
if ($tcp.client.connected)
{
[string]$rep=$tcp.client.RemoteEndPoint
[string]$ip=$rep.substring(0,$rep.indexof(":"))
$PortOpen=$True
$TTL=$($tcp.client.ttl)
$RemoteIP=$ip
}
else
{
Write-Verbose "$(Get-Date) $($computer.ToUpper()) not open on port: $port"
$PortOpen=$False
$TTL=-1
$RemoteIP=$Null
} #end Else
#disconnect the socket connection if open
if ($PortOpen)
{
Write-Verbose "$(Get-Date) Disconnecting from $($computer.ToUpper())"
$tcp.client.disconnect($False)
}
#write a custom object to the pipeline
New-Object -TypeName PSObject -Property @{
Computername=$Computer.ToUpper()
Port=$Port
Open=$PortOpen
TTL=$TTL
RemoteIP=$RemoteIP
}
} #end foreach $port
#dispose and disconnect
if ($tcp)
{
$tcp.close()
}
} #if shouldprocess
} #foreach $computer
} #end process
End {
Write-Progress -Activity $activity -status "Complete" -Completed
Write-Verbose "$(Get-Date) Ending $($myinvocation.mycommand)"
}#end
} #end function
[/cc]
The function supports -Whatif and -Confirm since scanning ports could be time consuming and something you may want to verify before you start scanning a large number of computers. You can pipe computer names to the function but the function will scan the same array of ports. The default array is 21, 22,23,25,80,443 and 3389. These are TCP ports by the way.
The function uses the .NET System.Net.Sockets.TcpClient class to open the port on the coimputer.
[cc lang="PowerShell"]
Try {
#create the TCPClient object
$tcp=New-Object System.Net.Sockets.TcpClient($computer, $port) -ErrorAction Stop
}
[/cc]
If the connection is made, the function retrieves some information and writes a custom object to the pipeline.
[cc lang="Powershell"]
#write a custom object to the pipeline
New-Object -TypeName PSObject -Property @{
Computername=$Computer.ToUpper()
Port=$Port
Open=$PortOpen
TTL=$TTL
RemoteIP=$RemoteIP
}
[/cc]
Because the function takes advantage of the pipeline, you can run an expression like this:
[cc lang="DOS"]
PS C:\> get-content computers.txt | Test-Port -port 80 | Where {$_.Open} | Out-File Open80.txt
[/cc]
This one line command will test all the computers listed in computer.txt for port 80 and save the results where true to Open80.txt. The function uses Write-Progress to provide feedback on what is being scanned. Write-Progress is not used as often as it could be and I think it's because there aren't enough practical examples, so I'm hoping this will help.
Enjoy and let me know what you think.
Download Test-Port.
awesome stuff, now I don’t need to install telnet every time I want to check a port !
Exactly. And I had PowerCLI in mind when I wrote it.