Last active
July 25, 2024 16:47
-
-
Save gabriel-vanca/e0eca5aec375f33c4cc0cf0f9af4ce4a to your computer and use it in GitHub Desktop.
Test-Port
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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