Skip to content

Instantly share code, notes, and snippets.

@gabriel-vanca
Last active July 25, 2024 16:47
Show Gist options
  • Save gabriel-vanca/e0eca5aec375f33c4cc0cf0f9af4ce4a to your computer and use it in GitHub Desktop.
Save gabriel-vanca/e0eca5aec375f33c4cc0cf0f9af4ce4a to your computer and use it in GitHub Desktop.
Test-Port
function Test-Port {
<#
.SYNOPSIS
Tests a Port or a range of ports on a specific ComputerName(s).
.DESCRIPTION
Tests a Port or a range of ports on a specific ComputerName(s). Creates a custom object with the properties: ComputerName, Protocol, Port, Open, Notes.
.PARAMETER ComputerName
A single ComputerName or array of ComputerName to test the port connection on. Aliased to 'CN', 'Server'
.PARAMETER Port
Port number to test ([int16] 0 - 65535), an array can also be passed
.PARAMETER TCP
Use TCP as the transport protocol
.PARAMETER UDP
Use UDP as the transport protocol
.PARAMETER TimeOut
Sets a timeout for TCP or UDP port query. (In milliseconds, Default is 1000)
.EXAMPLE
Test-Port -ComputerName 'server' -port 80
Checks port 80 on server 'server' to see if it is listening
.EXAMPLE
'server' | Test-Port -Port 80
Checks port 80 on server 'server' to see if it is listening
.EXAMPLE
"10.10.10.10" | Test-Port -Port 443
Checks ports 443 on machine with IP 10.10.10.10
.EXAMPLE
Test-Port -ComputerName @("server1","server2") -Port 80
Checks port 80 on server1 and server2 to see if it is listening
.EXAMPLE
@("server1","server2") | Test-Port -Port 80
Checks port 80 on server1 and server2 to see if it is listening
.EXAMPLE
(Get-Content hosts.txt) | Test-Port -Port 80
Checks port 80 on servers in host file to see if it is listening
.EXAMPLE
Test-Port -ComputerName (Get-Content hosts.txt) -Port 80
Checks port 80 on servers in host file to see if it is listening
.EXAMPLE
Test-Port -ComputerName (Get-Content hosts.txt) -Port @(1..59)
Checks a range of ports from 1-59 on all servers in the hosts.txt file
.OUTPUTS
[psobject]
An array of objects containing the fields:
ComputerName A string containing the computer name or ip address that was passed to the function
Protocol A string being either 'TCP' or 'UDP'
Port An integer in the range 1 - 65535
Open A boolean
Notes Any notes when attempting to make a connection
#>
#region Parameter
[CmdletBinding(ConfirmImpact = 'Low')]
[OutputType('psobject')]
Param(
[Parameter(Mandatory, HelpMessage = 'Enter a ComputerName or IP address', Position = 0, ValueFromPipeline)]
[Alias('CN', 'Server')]
[string[]] $computerList,
[Parameter(Position = 1, Mandatory, HelpMessage = 'Enter an integer port number (1-65535)')]
[string[]] $portList,
[int] $Timeout = 1000,
[switch] $TCP,
[switch] $UDP
)
#endregion Parameter
begin {
Write-Verbose -Message "Starting [$($MyInvocation.Mycommand)]"
Set-Variable -name PORTS_TABLE -option ReadOnly -Value ([System.Collections.Hashtable]([ordered]@{
Wake_on_LAN = 9;
FTP_Data = 20;
FTP_Command = 21;
SSH = 22;
TelNet = 23;
SMTP = 25;
WINS = 42;
DNS = 53;
DHCP_Server = 67;
DHCP_Client = 68;
TFTP = 69;
HTTP = 80;
HTTPS = 443;
Kerberos = 88;
POP3 = 110;
SFTP = 115;
NTP = 123;
RPC = 135;
NetBIOS_Name_Service = 137;
NetBIOS_Datagram_Service = 138;
NetBIOS_Session_Service = 139;
SNMP = 161;
LDAP = 389;
SMB = 445;
Syslog = 514;
LDAPS = 636;
SOCKS = 1080;
MSSQL = 1433;
SQL_Browser = 1434;
Oracle_DB = 1521;
NFS = 2049;
RDP = 3389;
XMPP = 5222;
HTTP_Proxy = 8080;
Global_Catalog = 3268;
Global_Catalog_SSL = 3269;
POP3_SSL = 995;
IMAP_SSL = 993;
IMAP = 143
}))
# Note the [System.StringComparer]::OrdinalIgnoreCase argument passed to the aux. dictionary, which ensures that key lookups are case-insensitive, the way they are by default in PowerShell [hashtables]
# Note that [hashtable] in Windows PowerShell and (obsolete) PowerShell Core versions 6.1 and below use [System.StringComparer]::CurrentCultureIgnoreCase
$tempPortsDict = [System.Collections.Generic.Dictionary[string, uint16]]::new([System.StringComparer]::OrdinalIgnoreCase)
foreach($port in $PORTS_TABLE.keys) {
$tempPortsDict.Add($port, [uint16] $PORTS_TABLE.$port)
}
# https://stackoverflow.com/questions/66857718/is-it-possible-to-create-a-non-modifiable-hashtable-in-powershell
Set-Variable -name PORTS_TABLE -option ReadOnly -Value ([System.Collections.ObjectModel.ReadOnlyDictionary[string, uint16]]::new($tempPortsDict)) -FORCE
Remove-Variable $tempPortsDict
if (!$tcp -AND !$udp) {
$tcp = $True
}
#Any errors will be noted in the output of the report
$oldEA = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
}
process {
foreach ($currentComputer in $computerList) {
foreach ($currentPort_generic in $portList) {
if($PORTS_TABLE.ContainsKey($currentPort_generic)) {
$currentPort = $PORTS_TABLE.$currentPort_generic
if (!$currentPort) {
Write-Error "No value for port $currentPort_generic"
continue
}
} else {
$currentPort = 0
try {
$currentPort = $currentPort_generic
} catch {
Write-Error $_
}
if($currentPort -eq 0) {
Write-Error "Port $currentPort_generic not acceptable"
continue
}
}
if ($tcp) {
#$report = '' | Select-Object -Property ComputerName, Protocol, Port, Open, Notes
$report = New-Object -TypeName psobject -Property ([ordered] @{ ComputerName = $currentComputer; Protocol = 'TCP'; Port = $currentPort; Open = $False; Notes = '' })
Write-Verbose -Message 'Making TCP connection to remote server'
#Create object for connecting to port on computer
$tcpobject = New-Object -TypeName system.Net.Sockets.TcpClient
#Connect to remote machine's port
$netConnection = $tcpobject.BeginConnect($currentComputer, $currentPort, $null, $null)
#Configure a timeout before quitting
$wait = $netConnection.AsyncWaitHandle.WaitOne($Timeout, $false)
#if timeout
if (!$wait) {
Write-Verbose -Message 'Connection Timeout'
#Build report
$report.Open = $false
$report.Notes = 'Connection to Port Timed Out'
} else {
$error.Clear()
$null = $tcpobject.EndConnect($netConnection)
#if unable to query port to due failure
if ($error[0]) {
#Build report
$report.Open = $false
$report.Notes = ((($error[0].exception).message.split(':')[1]).replace('"', '')).TrimStart()
} else {
#Build report
$report.Open = $true
$report.Notes = "Successful link to $currentComputer $($report.Protocol) port $currentPort"
}
}
#Close connection
$tcpobject.Close()
#Merge temp array with report
Write-Output -InputObject $report # | Select-Object -Property ComputerName, Protocol, Port, Open, Notes
Remove-Variable -Name report
}
if ($udp) {
#$report = '' | Select-Object -Property ComputerName, Protocol, Port, Open, Notes
$report = New-Object -TypeName psobject -Property ([ordered] @{ ComputerName = $currentComputer; Protocol = 'UDP'; Port = $currentPort; Open = $False; Notes = '' })
Write-Verbose -Message 'Making UDP connection to remote server'
$Socket = New-Object -TypeName Net.Sockets.Socket -ArgumentList ( 'InterNetwork', 'Dgram', 'Udp' )
$Socket.SendTimeOut = $Timeout # ms
$Socket.ReceiveTimeOut = $Timeout # ms
try {
$Socket.Connect( $currentComputer, $currentPort )
$Buffer = New-Object -TypeName byte[] -ArgumentList 48
$Buffer[0] = 27
Write-Verbose -Message 'Sending message to remote host'
$null = $Socket.Send($Buffer)
$null = $Socket.Receive($Buffer)
$report.Open = $true
$report.Notes = "Successful link to $currentComputer $($report.Protocol) port $currentPort"
} catch {
Write-Verbose -Message 'Communication failed'
Write-Verbose -Message $error[0]
$report.Open = $false
$report.Notes = $error[0].exception
}
$socket.dispose()
Remove-Variable -Name socket
#Merge temp array with report
Write-Output -InputObject $report # | Select-Object -Property ComputerName, Protocol, Port, Open, Notes
Remove-Variable -Name report
}
}
}
}
end {
#Generate Report
#Write-Output -InputObject $report
Remove-Variable $PORTS_TABLE -FORCE
Write-Verbose -Message "Resetting value of `$ErrorActionPreference back to [$($oldEa)]"
$ErrorActionPreference = $oldEA
Write-Verbose -Message "Ending [$($MyInvocation.Mycommand)]"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment