Test-NetConnection — готовый к использованию командлет для проверки сетевого подключения появился в PowerShell 4.0 (Windows 2012 R2, Windows 8.1 и новее). Этот командлет можно использовать для проверки ответа и доступности удалённого сервера или сетевой службы на нём, портов TCP, заблокированных брандмауэрами, проверки доступности и маршрутизации ICMP. Фактически, командлет Test-NetConnection может заменить сразу несколько стандартных инструментов сетевого администрирования: ping, traceroute, сканер TCP-портов и т. д.
Время от времени любой администратор должен проверять доступность службы на удалённом сервере, проверяя ответ удалённого TCP-порта (например, доступность электронной почты или веб-сервера). Более того, большинство администраторов используют для выполнения такой проверки порта с помощью команды telnet. Например, чтобы убедиться, что служба SMTP отвечает на почтовом сервере (по умолчанию она отвечает на TCP-порту 25), достаточно выполнить команду
telnet mail.site.com 25
Но начиная с Windows 7, клиент telnet стал функцией, которую нужно устанавливать отдельно. Давайте посмотрим, как проверить открытые/закрытые TCP-порты с помощью PowerShell.
Основное преимущество командлета Test-NetConnection заключается в том, что он уже входит в состав всех современных версий Windows, и вам не нужно устанавливать его отдельно. Командлет является частью модуля NetTCPIP (начиная с PoSh v4.0).
Подсказка: вы можете проверить текущую установленную версию PowerShell с помощью команды:
$PSVersionTable.PSVersion
Значение 7 в столбце Major означает, что на вашем компьютере установлена оболочка PowerShell 7.2.
Тестирование открытости/закрытости TCP-портов с помощью Test-NetConnection
Давайте проверим, открыт ли (доступен) TCP-порт 80 (протокол HTTP) на удалённом почтовом сервере, используя Test-NetConnection:
Test-NetConnection -ComputerName hackware-arch -Port 80
Примечание: используя командлет Test-NetConnection, вы можете проверить только подключение к порту TCP, и он не применим для проверки доступности удалённых портов UDP.
Укороченная версия той же команды выглядит так:
TNC hackware-arch -Port 80
Рассмотрим результат выполнения команды:
ComputerName : hackware-arch RemoteAddress : 192.168.0.88 RemotePort : 80 InterfaceAlias : Ethernet SourceAddress : 192.168.0.101 TcpTestSucceeded : True
Как видите, командлет преобразует имя сервера в IP-адрес и проверяет доступность порта TCP. На указанном сервере TCP-порт 80 (RemotePort : 80) открыт (TcpTestSucceeded : True).
Командлет имеет специальный параметр -CommonTCPPort, который позволяет указать имя известного сетевого протокола (HTTP, RDP, SMB, WINRM).
Например, чтобы проверить доступность веб-сервера HTTP, вы можете использовать команду:
Test-NetConnection -ComputerName hackware-arch -CommonTCPPort HTTP
Или открытость порта RDP (3389):
Test-NetConnection ny-rds1 -CommonTCPPort RDP
Вы можете перечислить все параметры, которые возвращает командлет Test-NetConnection:
Test-NetConnection hackware-arch -port 80 | Format-List *
Обратите внимание на строку в выводе:
PingSucceeded : False
Это означает следующее:
- Перед проверкой порта командлет пытается выполнить пинг
- В данном случае компьютер не ответил на пинг (такое бывает — даже включенные компьютеры не обязаны отвечать на пинг, это можно изменить в настройках файервола)
- Даже при неудачном пинге Test-NetConnection всё равно проверяет доступность порта
Если вам нужно только посмотреть, доступен ли порт, его можно проверить быстрее:
TNC hackware-arch -port 80 -InformationLevel Quiet
Командлет вернул True, что означает, что удалённый порт открыт.
Подсказка: в более ранних версиях PowerShell вы могли проверить доступность TCP-порта следующим образом:
(New-Object System.Net.Sockets.TcpClient).Connect('hackware-arch', 80)
В Windows 10/Windows Server 2016 вы можете использовать командлет Test-NetConnection для отслеживания маршрута к удалённому серверу с помощью параметра -TraceRoute (аналог команды tracert в Windows). Параметр -Hops позволяет ограничить максимальное количество хопов (узлов) при проверке маршрута.
Test-NetConnection suip.biz -TraceRoute
Связанная статья: Трассировка сетевого маршрута
Командлет вернул суммарную задержку сети при доступе к серверу в миллисекундах (PingReplyDetails (RTT) : 36 ms) и все IP-адреса маршрутизаторов на пути к целевому серверу.
Test-NetConnection в скриптах мониторинга PowerShell
Следующая команда позволяет вам проверить доступность определённого порта на нескольких серверах, список которых хранится в текстовом файле list_servers.txt (расположен в папке c:PS). Нам нужны серверы, на которые не отвечает указанный сервис:
Get-Content c:PSlist_servers.txt | where { -NOT (Test-Netconnection $_ -Port 25 -InformationLevel Quiet)}| Format-Table -AutoSize
Точно так же вы можете создать простой скрипт мониторинга, который проверяет доступность серверов и отображает уведомление, если один из серверов недоступен.
Например, вы можете проверить доступность базовых служб на всех контроллерах домена (список контроллеров домена можно получить с помощью командлета Get-ADDomainController). Давайте проверим следующие службы на DC (инструмент PortQry имеет аналогичное правило «Domain and trusts»):
- RPC – TCP/135
- LDAP – TCP/389
- LDAP – TCP/3268
- DNS – TCP/53
- Kerberos – TCP/88
- SMB – TCP/445
Скрипт проверит указанные TCP-порты на контроллерах домена, и, если один из портов недоступен, он выделит его красным цветом (вы можете запустить этот скрипт PowerShell как службу Windows).
$Ports = "135","389","636","3268","53","88","445","3269", "80", "443" $AllDCs = Get-ADDomainController -Filter * | Select-Object Hostname,Ipv4address,isGlobalCatalog,Site,Forest,OperatingSystem ForEach($DC in $AllDCs) { Foreach ($P in $Ports){ $check=Test-NetConnection $DC -Port $P -WarningAction SilentlyContinue If ($check.tcpTestSucceeded -eq $true) {Write-Host $DC.name $P -ForegroundColor Green -Separator " => "} else {Write-Host $DC.name $P -Separator " => " -ForegroundColor Red} } }
А это чуть модифицированная версия скрипта, в которой список серверов считывается из файла C:UsersMiAlDocumentslist_servers.txt, а также выводятся имена хостов, чтобы было понятно, чьи именно порты проверяются:
$Ports = "135","389","636","3268","53","88","445","3269", "80", "443" $AllHosts = Get-Content C:UsersMiAlDocumentslist_servers.txt ForEach($Hosts in $AllHosts) { $Hosts Foreach ($P in $Ports){ $check=Test-NetConnection $Hosts -Port $P -WarningAction SilentlyContinue If ($check.tcpTestSucceeded -eq $true) {Write-Host $Hosts.name $P -ForegroundColor Green -Separator " => "} else {Write-Host $Hosts.name $P -Separator " => " -ForegroundColor Red} } }
Код скрипта сохранён в файл port_checker.ps1, пример запуска:
C:UsersMiAlDocumentsport_checker.ps1
Простой сканер IP-сетей/портов с помощью PowerShell
Вы также можете реализовать простой сетевой сканер портов и IP-подсетей для сканирования удалённых серверов или подсетей на предмет открытых/закрытых TCP-портов.
Просканируем диапазон IP-адресов в поисках открытого порта 80:
foreach ($ip in 100..150) {Test-NetConnection -Port 80 -InformationLevel "Detailed" 192.168.1.$ip}
А этот пример просканирует диапазон TCP-портов от 1 до 1024 на указанном удалённом сервере:
foreach ($port in 1..1024) {If ((Test-NetConnection 192.168.0.88 -Port $port -WarningAction SilentlyContinue).tcpTestSucceeded -eq $true){ "TCP port $port is open!"}}
Скорость проверки, конечно, оставляет желать лучшего.
Test-NetConnection в Linux
На момент написания, в Linux командлет Test-NetConnection отсутствует
Но старый способ проверки открытых портов работает:
(New-Object System.Net.Sockets.TcpClient).Connect('suip.biz', 80)
Связанные статьи:
- Как в PowerShell просмотреть открытые порты. Как узнать, какая программа прослушивает порт (100%)
- Как в PowerShell просмотреть открытые порты UDP (72%)
- Использование PortQry для проверки открытых портов TCP/UDP (сканер портов) (64%)
- Как в PowerShell установить IP, маску сети, шлюз по умолчанию и DNS для сетевого интерфейса (58%)
- Как в PowerShell настроить сетевой интерфейс на использование динамичного IP адреса (DHCP) (58%)
- Как настроить Windows Server 2022 с помощью PowerShell (RANDOM — 8%)
В PowerShell 4.0 (Windows 2012 R2, Windows 8.1 и выше) появился встроенный командлет для проверки сетевых соединений — Test-NetConnection. С помощью данного командлета вы можете проверить доступность удаленного сервера или сетевой службы на нем, блокировку TCP портов файерволами, проверить доступность по ICMP и маршрутизацию. По сути, командлет
Test-NetConnection
позволяет заменить сразу несколько привычных сетевых утилит: ping, traceroute, сканер TCP портов и т.д.
Содержание:
- TCP Port Ping: Использование Test-NetConnection для проверки открытых портов и доступности серверов
- Test-NetConnection в скриптах мониторинга
- Сканер сети на PowerShell
Любому администратору периодически приходится проверять доступность службы на удаленном сервере путем проверки ответа от удаленного TCP порта (например, доступность почтового или веб сервера). Причем, все привыкли, что такую проверку быстрее всего выполнить с помощью команды telnet. Например, для проверки доступности SMTP службы на почтовом сервере (по умолчанию он отвечает на 25 TCP порту) достаточно выполнить команду
telnet msk-msg01.winitpro.ru 25
. Но начиная с Windows 7 клиент telnet выделен в отдельный компонент, который нужно устанавливать отдельно. Посмотрим, как выполнить аналогичное действие в PowerShell.
Основное преимущество командлета Test-NetConnection – он уже входит в состав всех современных версий Windows и вам не нужно устанавливать его отдельно. Командлет входит в состав модуля NetTCPIP (начиная с PoSh v4.0).
TCP Port Ping: Использование Test-NetConnection для проверки открытых портов и доступности серверов
Проверим, открыт ли порт TCP 25 (SMTP протокол) на почтовом сервере с помощью Test-NetConnection:
Test-NetConnection -ComputerName msk-msg01 -Port 25
Примечание. С помощью командлета Test-NetConnection можно проверить только TCP соединение, для проверки доступности UDP портов он не применим.
В сокращенном виде аналогичная команда выглядит так:
TNC msk-mail1 -Port 25
Разберем результат команды:
ComputerName : msk-msg01 RemoteAddress : 10.10.1.7 RemotePort : 25 InterfaceAlias : CORP SourceAddress : 10.10.1.70 PingSucceeded : True PingReplyDetails (RTT) : 0 ms TcpTestSucceeded : True
Как вы видите, командлет выполняет разрешение имени сервера в IP адрес, выполняется проверка ответа ICMP (аналог ping) и доступность TCP порта. Указанный сервер доступен по ICMP (
PingSucceeded = True
) и 25 TCP порт также отвечает (
RemotePort=25, TcpTestSucceeded= True
).
Примечание. В некоторых случаях может оказаться, что PingSucceeded=False, а TcpTestSucceeded= True. Скорее всего означает, что на удаленном сервере запрещен ICMP Ping.
У командлета есть специальный параметр –CommonTCPPort, позволяющий указать наименование известного сетевого протокола (HTTP, RDP, SMB, WINRM).
Например, чтобы проверить доступность веб-сервера, можно использовать команду:
Test-NetConnection -ComputerName winitpro.ru -CommonTCPPort HTTP
Или доступность RDP порта (3389):
Test-NetConnection msk-rds1 –CommonTCPPort RDP
Можно вывести все параметры, которые возвращает командлет Test-NetConnection:
Test-NetConnection msk-man01 -port 445|Format-List *
Если нужна только информация по доступности TCP порта, в более лаконичном виде проверка может быть выполнена так:
TNC msk-mail1 -Port 25 -InformationLevel Quiet
Командлет вернул True, значит удаленный порт доступен.
Совет. В предыдущих версиях PowerShell проверить доступность удаленного TCP порта можно так:
(New-Object System.Net.Sockets.TcpClient).Connect(‘msk-msg01’, 25)
В Windows 10/ Windows Server 2016 вы можете использовать командлет Test-NetConnection для трассировки маршрута до удаленного сервера при помощи параметра –TraceRoute (аналог tracert). С помощью параметра –Hops можно ограничить максимальное количество хопов при проверке.
Test-NetConnection msk-man01 –TraceRoute
Командлет вернул сетевую задержку при доступе к серверу в милисекундах (
PingReplyDetails (RTT) : 41 ms
) и все IP адреса маршрутизаторов на пути до целевого сервера.
Test-NetConnection в скриптах мониторинга
Следующая команда позволить проверить доступность определенного порта на множестве серверов, список которых хранится в текстовом файле servers.txt. Нас интересуют сервера, где искомая служба не отвечает:
Get-Content c:Distrservers.txt | where { -NOT (Test-Netconnection $_ -Port 25 -InformationLevel Quiet)}| Format-Table –AutoSize
Аналогичным образом вы можете создать простейшую систему мониторинга, которая проверяет доступность серверов и выводит уведомление, если один из серверов недоступен.
Например, вы можете проверить доступность основных служб на всех контроллеров домена (список DC можно получить командлетом Get-ADDomainController). Проверим следующие службы на DC (в утилите PortQry есть аналогичное правило Domain and trusts):
- RPC – TCP/135
- LDAP – TCP/389
- LDAP – TCP/3268
- DNS – TCP/53
- Kerberos – TCP/88
- SMB – TCP/445
$Ports = "135","389","636","3268","53","88","445","3269", "80", "443"
$AllDCs = Get-ADDomainController -Filter * | Select-Object Hostname,Ipv4address,isGlobalCatalog,Site,Forest,OperatingSystem
ForEach($DC in $AllDCs)
{
Foreach ($P in $Ports){
$check=Test-NetConnection $DC -Port $P -WarningAction SilentlyContinue
If ($check.tcpTestSucceeded -eq $true)
{Write-Host $DC.name $P -ForegroundColor Green -Separator " => "}
else
{Write-Host $DC.name $P -Separator " => " -ForegroundColor Red}
}
Скрипт проверит указанные TCP порты на контроллерах домена, и, если один из портов недоступен, выделит его красным цветом (с небольшими доработками можно запустить данный PowerShell скрипт как службу Windows).
Сканер сети на PowerShell
Также вы можете реализовать простой сканер портов и IP подсетей для сканирования удаленных серверов или подсетей на открытые/закрытые TCP порты.
Просканируем диапазон IP адресов на открытый порт 3389:
foreach ($ip in 5..30) {Test-NetConnection -Port 3389 -InformationLevel "Detailed" 10.10.10.$ip}
Просканируем диапазон TCP портов от 1 до 1024 на указанном сервере:
foreach ($port in 1..1024) {If (($a=Test-NetConnection srvfs01 -Port $port -WarningAction SilentlyContinue).tcpTestSucceeded -eq $true){ "TCP port $port is open!"}}
It was brought to my attention earlier in the week that my Test-Port script had a fairly big bug involving checking the UDP port to determine whether it was open or not. Initially, the function would always come back with a True statement giving a false positive that the port was open, when in fact it was not. In the case of the bug report, the system in question was actually turned off, making it even more of a false positive. The reason behind this is that sending out a message or request via UDP does not guarantee that a response will be given back, unlike TCP where you will know pretty quickly if the port is open or closed. More information here, here and here.
So with that, I set off to find a good way of querying for an open UDP port. I immediately went to the MSDN page for the System.Net.Sockets.UDPClient to see what methods were available to me. I also took note of the example that was given for making a UDP connection and receiving a message from that port. Since this was written in C#, I knew I could easily translate this into PowerShell (and in fact I left a community contribution on the page).
There are some gotchas here that I will share with you that I came across while working on this. I can tell you that one of these caused me some pain as it made the executed code hang forever.
The first thing we need to do is create the UDPClient object. Using a constructor, I am opening the local UDP port on my laptop using port 11000:
$udpobject = new-Object system.Net.Sockets.Udpclient(11000)
Now that I have my object created, I can now proceed to set up my message string that will be sent along with actually sending out the data. The trick here with sending out a message via the UDPclient is that it must be in bytes. So while I supply a string message to send, it must be converted into a byte format. This is done by using the System.Text.ASCIIEncoding class. For this message, I will just send a date string to the remote server.
$a = new-object system.text.asciiencoding $byte = $a.GetBytes("$(Get-Date)")
Ok, now lets create the “connection” to the remote server using the Connect() method. This method requires us to supply a hostname and port to connect on. I say “connection” because even if the port isn’t open, it will still act like a connection was made. You will only receive an error if the host does not exist, or is not on the network.
$udpobject.Connect("dc1",11000)
Now lets send the message to the remote host. Again, just like making the connection, we will not receive any sort of response if the send was successful or not. By doing this, we are forcing some sort of response by the port, either it will receive the data, or we will receive an error stating the port was closed.
[void]$udpobject.Send($byte,$byte.length)
After sending the data, we now need to setup the receiving portion of the code. The Receive() method requires the System.Net.IPEndpoint class to be supplied. That can be created using the following code by declaring that we are looking for data sent to us from any source.
#IPEndPoint object will allow us to read datagrams sent from any source. $remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)
The 0 stands for any port and [System.Net.IPAddress]::Any means from any host.
Now that I have created an endpoint, lets now set the udp object to wait until a response is given back from the host which we sent the data to. We will also read the response back from the remote host.
#Blocks until a message returns on this socket from a remote host. $receivebytes = $udpobject.Receive([ref]$remoteendpoint) #Convert returned data into string format [string]$returndata = $a.GetString($receivebytes) #Uses the IPEndPoint object to show that the host responded. Write-Host "This is the message you received: $($returndata.ToString())" Write-Host "This message was sent from: $($remoteendpoint.address.ToString()) on their port number: $($remoteendpoint.Port.ToString())"
Let’s assume that the port is closed on the remote host. Running the first line of the code will produce an error such as the one below.
Luckily, this error can be caught using Try/Catch so you can easily write to a log or anything else if this happens. Ok, so we know how to tell if a UDP port is closed on a remote machine, but what is going to happen if that port is open? Let’s find out. I am going to open a UDP port on my server, DC1 and then we will run the same code to see what happens.
First, lets open up that port on DC1:
Perfect, now lets re-run the same code and see what happens:
Cool, no errors and now we are just waiting for a response back from the remote server.
10 minutes later… (crickets chirping)
Hmmm… nothing at all being returned. You might think that the code is hung or something else is going on. And you are right about something else going on. Remember what I said earlier about how UDP works? It will not return anything to use even if you send data to that port. So in effort, this wait will basically go on forever.
Here is a gotcha that I was telling you about. One way to resolve this is by setting a timeout on the receiving of data. To do this, you need to look at the properties of the $udpobject object we created:
PS C:Usersboe> $udpobject | Format-List *
Client : System.Net.Sockets.Socket
Available : 0
Ttl : 64
DontFragment : False
MulticastLoopback : True
EnableBroadcast : False
ExclusiveAddressUse : False
Take note of the client property which consists of the System.Net.Sockets.Socket class. Within this class is where we need to make a slight adjustment to the receiving timeout. Now we will expand out the Client property to find out where we need to make that change.
PS C:Usersboe> $udpobject.client
Available : 0
LocalEndPoint : 0.0.0.0:11000
RemoteEndPoint :
Handle : 1364
Blocking : True
UseOnlyOverlappedIO : False
Connected : False
AddressFamily : InterNetwork
SocketType : Dgram
ProtocolType : Udp
IsBound : True
ExclusiveAddressUse : False
ReceiveBufferSize : 8192
SendBufferSize : 8192
ReceiveTimeout : 0
SendTimeout : 0
LingerState :
NoDelay :
Ttl : 64
DontFragment : False
MulticastLoopback : True
EnableBroadcast : False
And there it is, the ReceiveTimeout property. Currently, it is set to 0, meaning that this will never timeout. Keep in mind that the value you supply will be in milliseconds. I will go ahead and set this to 10000 milliseconds and now we will re-run the code again to see what happens.
Now, after 10 seconds, we get the error stating:
Exception calling “Receive” with “1” argument(s): “A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond”
Setting the timeout now allows the code to error out when the port is open so it does not wait forever for a response back. Plus, this can be caught with a Try/Catch statement so we can parse the error and show that the port is open on the system. One more gotcha is that if the server is powered down, but still in DNS, then the error will still occur instead of automatically reporting an error. So keep that in mind. In fact, performing a ping test (or Test-Connection) prior to making the port check would be recommended.
Sending and Receiving a Message
Ok, now for something fun. I am going to go onto DC1 and send a response to my laptop on the same port. So instead of a timeout, you will see the message and the ip and port that the message responded back on.
Lets start it off by opening port 11000 on DC1 and connecting to my laptop.
$udp = new-object System.Net.Sockets.Udpclient(11000) $udp.Connect("boe-laptop",11000)
Now we create our UDP object here and wait for our message to be sent from DC1. For this I will not specify a timeout as I need to run some code on DC1. Most of the code will not run until it has received a message from DC1.
$udpobject = new-Object system.Net.Sockets.Udpclient(11000) $remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0) $receivebytes = $udpobject.Receive([ref]$remoteendpoint) [string]$returndata = $a.GetString($receivebytes) Write-Host -fore green "This is the message you received: $($returndata.ToString())" Write-Host -fore green "This message was sent from: $($remoteendpoint.address.ToString()) on their port number: $($remoteendpoint.Port.ToString())"
Now the command is waiting for a message from DC1. Lets go back to DC1 and create a message from a string and convert it into bytes. Once converted to bytes, we can then send the message to the waiting laptop.
$a = New-Object system.text.asciiencoding $byte = $a.GetBytes("This message sent from DC1 to boe-laptop") $udp.Send($byte,$byte.length)
If you have both windows available to view. You will notice that as soon as you perform the Send() method, the waiting PowerShell console will immediately process the message and display the results.
Pretty cool, isn’t it? You could go back and forth between these to systems and send messages if you wanted to.
That wraps it up for my post on working with UDP ports in PowerShell. As you can see, it is pretty easy to find out if a UDP port is actually open as long as you have a timeout specified in the UDPClient.Client properties. Once you do that, just some simple parsing of the error can determine if the port was open or closed.
Code
I am going to reference my Test-Port function I wrote a while back that is now updated with the UDP code bug fix.
Script Repository
PoshCode
function Test-Port{ <# .SYNOPSIS Tests port on computer. .DESCRIPTION Tests port on computer. .PARAMETER computer Name of server to test the port connection on. .PARAMETER port Port to test .PARAMETER tcp Use tcp port .PARAMETER udp Use udp port .PARAMETER UDPTimeOut Sets a timeout for UDP port query. (In milliseconds, Default is 1000) .PARAMETER TCPTimeOut Sets a timeout for TCP port query. (In milliseconds, Default is 1000) .NOTES Name: Test-Port.ps1 Author: Boe Prox DateCreated: 18Aug2010 List of Ports: http://www.iana.org/assignments/port-numbers To Do: Add capability to run background jobs for each host to shorten the time to scan. .LINK https://boeprox.wordpress.org .EXAMPLE Test-Port -computer '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 Test-Port -computer @("server1","server2") -port 80 Checks port 80 on server1 and server2 to see if it is listening .EXAMPLE Test-Port -comp dc1 -port 17 -udp -UDPtimeout 10000 Server : dc1 Port : 17 TypePort : UDP Open : True Notes : "My spelling is Wobbly. It's good spelling but it Wobbles, and the letters get in the wrong places." A. A. Milne (1882-1958) Description ----------- Queries port 17 (qotd) on the UDP port and returns whether port is open or not .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 -computer (Get-Content hosts.txt) -port 80 Checks port 80 on servers in host file to see if it is listening .EXAMPLE Test-Port -computer (Get-Content hosts.txt) -port @(1..59) Checks a range of ports from 1-59 on all servers in the hosts.txt file #> [cmdletbinding( DefaultParameterSetName = '', ConfirmImpact = 'low' )] Param( [Parameter( Mandatory = $True, Position = 0, ParameterSetName = '', ValueFromPipeline = $True)] [array]$computer, [Parameter( Position = 1, Mandatory = $True, ParameterSetName = '')] [array]$port, [Parameter( Mandatory = $False, ParameterSetName = '')] [int]$TCPtimeout=1000, [Parameter( Mandatory = $False, ParameterSetName = '')] [int]$UDPtimeout=1000, [Parameter( Mandatory = $False, ParameterSetName = '')] [switch]$TCP, [Parameter( Mandatory = $False, ParameterSetName = '')] [switch]$UDP ) Begin { If (!$tcp -AND !$udp) {$tcp = $True} #Typically you never do this, but in this case I felt it was for the benefit of the function #as any errors will be noted in the output of the report $ErrorActionPreference = "SilentlyContinue" $report = @() } Process { ForEach ($c in $computer) { ForEach ($p in $port) { If ($tcp) { #Create temporary holder $temp = "" | Select Server, Port, TypePort, Open, Notes #Create object for connecting to port on computer $tcpobject = new-Object system.Net.Sockets.TcpClient #Connect to remote machine's port $connect = $tcpobject.BeginConnect($c,$p,$null,$null) #Configure a timeout before quitting $wait = $connect.AsyncWaitHandle.WaitOne($TCPtimeout,$false) #If timeout If(!$wait) { #Close connection $tcpobject.Close() Write-Verbose "Connection Timeout" #Build report $temp.Server = $c $temp.Port = $p $temp.TypePort = "TCP" $temp.Open = "False" $temp.Notes = "Connection to Port Timed Out" } Else { $error.Clear() $tcpobject.EndConnect($connect) | out-Null #If error If($error[0]){ #Begin making error more readable in report [string]$string = ($error[0].exception).message $message = (($string.split(":")[1]).replace('"',"")).TrimStart() $failed = $true } #Close connection $tcpobject.Close() #If unable to query port to due failure If($failed){ #Build report $temp.Server = $c $temp.Port = $p $temp.TypePort = "TCP" $temp.Open = "False" $temp.Notes = "$message" } Else{ #Build report $temp.Server = $c $temp.Port = $p $temp.TypePort = "TCP" $temp.Open = "True" $temp.Notes = "" } } #Reset failed value $failed = $Null #Merge temp array with report $report += $temp } If ($udp) { #Create temporary holder $temp = "" | Select Server, Port, TypePort, Open, Notes #Create object for connecting to port on computer $udpobject = new-Object system.Net.Sockets.Udpclient #Set a timeout on receiving message $udpobject.client.ReceiveTimeout = $UDPTimeout #Connect to remote machine's port Write-Verbose "Making UDP connection to remote server" $udpobject.Connect("$c",$p) #Sends a message to the host to which you have connected. Write-Verbose "Sending message to remote host" $a = new-object system.text.asciiencoding $byte = $a.GetBytes("$(Get-Date)") [void]$udpobject.Send($byte,$byte.length) #IPEndPoint object will allow us to read datagrams sent from any source. Write-Verbose "Creating remote endpoint" $remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0) Try { #Blocks until a message returns on this socket from a remote host. Write-Verbose "Waiting for message return" $receivebytes = $udpobject.Receive([ref]$remoteendpoint) [string]$returndata = $a.GetString($receivebytes) If ($returndata) { Write-Verbose "Connection Successful" #Build report $temp.Server = $c $temp.Port = $p $temp.TypePort = "UDP" $temp.Open = "True" $temp.Notes = $returndata $udpobject.close() } } Catch { If ($Error[0].ToString() -match "bRespond after a period of timeb") { #Close connection $udpobject.Close() #Make sure that the host is online and not a false positive that it is open If (Test-Connection -comp $c -count 1 -quiet) { Write-Verbose "Connection Open" #Build report $temp.Server = $c $temp.Port = $p $temp.TypePort = "UDP" $temp.Open = "True" $temp.Notes = "" } Else { <# It is possible that the host is not online or that the host is online, but ICMP is blocked by a firewall and this port is actually open. #> Write-Verbose "Host maybe unavailable" #Build report $temp.Server = $c $temp.Port = $p $temp.TypePort = "UDP" $temp.Open = "False" $temp.Notes = "Unable to verify if port is open or if host is unavailable." } } ElseIf ($Error[0].ToString() -match "forcibly closed by the remote host" ) { #Close connection $udpobject.Close() Write-Verbose "Connection Timeout" #Build report $temp.Server = $c $temp.Port = $p $temp.TypePort = "UDP" $temp.Open = "False" $temp.Notes = "Connection to Port Timed Out" } Else { $udpobject.close() } } #Merge temp array with report $report += $temp } } } } End { #Generate Report $report } }
Introducing another addition to our portfolio of minimalistic tools for pentesting. This time we are going to be looking on a minimalistic TCP and UDP port scanner.
Written in pure PowerShell, this small yet powerful port scanner is useful in specific attack simulations where we cannot use any traditional or typical port scanners.
- Introduction
- Why writing port scanner from scratch?
- TCP and UDP port scanner in PowerShell
- List of features
- Typical usage scenario
- Port scan of a single host
- Port scan of a network range
- List of hosts in a file
- Getting the results
- Requirements and limitations
- Conclusion
- See also
Introduction
There are many network port scanners out there. Some of the most popular ones include Nmap, Masscan, Angry IP Scanner, ZMap any there are plenty of others.
They are all great, well tested and functional, but they are also big, complex and most importantly flagged by every decent Antivirus or EDR solution. And that can be a deal breaker in some penetration testing scenarios.
In some situations we simply need something small and minimalistic, something that we could write from scratch quickly, if we needed to.
Why writing port scanner from scratch?
Writing tools from scratch may be necessary, for instance, when we are performing pentest from a heavily restricted environment where we cannot use any typical pentesting tools.
This would be vital while testing of an isolated VDI / Citrix environment where we cannot upload anything or when we are performing a simulation of a disgruntled employee from a workstation with all the security controls in place.
In all these cases we would need to build our own tools in order for us to be able to perform basic operations such as port scanning.
Without port scanning abilities, we would hardly be able to make any progress, discover systems on the network, or perform any lateral movement for that matter.
Port scanner is simply a must and if we cannot use one, we have to make one.
For such occasions, I have developed the following quick and easy, but powerful and reliable port scanner.
To keep the size small, I have divided the scanner into two separate independent modules:
- TCP port scanner: port-scan-tcp.ps1
- UDP port scanner: port-scan-udp.ps1
So it’s really two port scanners, not one. Both scanners can be found in the following GitHub repository:
- https://github.com/InfosecMatter/Minimalistic-offensive-security-tools
List of features
Both port scanners have the following features:
- Detection of open, closed and filtered ports (both TCP and UDP)
- Ability to scan a single host, network range or a list of hosts in a file
- Adjustable timeout values for effective and reliable port scanning
- Non-malicious – undetected by any Antivirus or EDR solution
From the design point of view:
- Small and minimalistic – can be typed out by hand (on the keyboard)
- Written in pure PowerShell – no additional modules needed
- Practical and smart design:
- Support resuming, if interrupted
- Skip already scanned hosts / ports
Let’s have a look on how to use these scanners.
Typical usage scenario
Since the port scanners are written in PowerShell, we have to be able to run PowerShell commands on the system that we are using. On a restricted workstation this may a be a problem, so..
(1) First step is typically to circumvent the restrictions and spawn a shell. Once we can comfortably run PowerShell commands, we can progress to the next step.
(2) Now we can write up the port scanners somewhere on the file system. For instance, we could place them on our Desktop, but due to various restrictions we may have to place them somewhere else where we can write, e.g.:
- C:UsersPublic
- C:WindowsTasks
- C:WindowsTracing
- C:WindowsSystem32SpoolDriversColor
- etc.
And that’s all!
Now we can start doing some port scanning. Here’s a quick intro into how to use them.
TCP port scanner:
Import-Module .port-scan-tcp.ps1
# Usage:
port-scan-tcp <host(s)> <port(s)>
UDP port scanner:
Import-Module .port-scan-udp.ps1
# Usage:
port-scan-udp <host(s)> <port(s)>
Let’s see some examples on how to use them in practice.
Port scan of a single host
Here’s the simplest example – check if a remote host has port tcp/445 open:
port-scan-tcp 192.168.204.183 445
Here’s an example of port scanning a single host for selected tcp ports:
port-scan-tcp 192.168.204.183 (21,22,23,25,80,443,445,3389)
Port scan of a network range
Here’s an example of port scanning a network range 192.168.204.0/24 for port tcp/445 (port sweeping):
0..255 | foreach { port-scan-tcp 192.168.204.$_ 445 }
Here’s an example of port scanning a network range 192.168.204.0/24 for selected tcp ports:
0..255 | foreach { port-scan-tcp 192.168.204.$_ (22,80,445) }
List of hosts in a file
We can also provide list of targets as an input file.
For instance, in corporate networks with Active Directory (AD) deployment, we could extract list of computers from AD using PowerShell cmdlets like this:
$a = [adsisearcher]”(objectCategory=computer)”
$a.PropertiesToLoad.add(“dnshostname”) | out-null
$a.PageSize = 1
$a.FindAll() | % { echo $_.properties.dnshostname } > computers.txt
Now we could identify all alive Windows systems by port sweeping on port tcp/445:
port-scan-tcp (gc .computers.txt) 445
Getting the results
Both scanners keep track of everything using a state file (scanresults.txt) which is created in the current working directory. This allows us to check on the results anytime, even during ongoing scans.
For instance, here’s how we can get a list systems with port tcp/445 open:
Get-Content .scanresults.txt | Select-String "tcp,445,Open"
If we wanted to list only the first column, we could easily do that with PowerShell like this:
(Get-Content .scanresults.txt | Select-String "tcp,445,Open") -replace ",.*",""
Now we could feed this list into our SMB login bruteforcer, for instance, and attempt to compromise some of these Windows machines. Or we could employ some other automation, anything we would like.
Requirements and limitations
Compatibility. The TCP scanner comes in two versions with the difference of using the TcpClient.ConnectAsync() method. This method, available in .NET 4.5, gives the scanner ability to discern between ‘Closed’ and ‘Filtered’ ports. The compat version of the scanner (for older systems) cannot discern this and just reports both such cases as ‘Closed’.
Speed. Both port scanners (TCP and UDP) are only a single threaded loops without any parallelization. Thus, the scanning speed is limited. But, in the worst case the speed should be around 1 port scan per second, depending on the timeout values which you can also simply just change.
Speed degradation. Something to also keep in mind is that the scanners may get a bit slow after some time if there are too many results already. To mitigate this issue, we can rotate the results file or use a different one by modifying the modules and reloading:
Import-Module .port-scan-tcp.ps1 -force
Import-Module .port-scan-udp.ps1 -force
Conclusion
Although these port scanners are not perfect, in some situations they are exactly what gets the job done with a nice feature list and compact form.
Hope you will find them useful too sometimes!
If you like these tools and you would like more like it, please subscribe to my mailing list and follow me on Twitter, Facebook or Github to get notified about new additions!
See also
- Active Directory Brute Force Attack Tool in PowerShell (ADLogin.ps1)
- Windows Local Admin Brute Force Attack Tool (LocalBrute.ps1)
- SMB Brute Force Attack Tool in PowerShell (SMBLogin.ps1)
I was trying to check whether the port is opened or not using powershell like follows.
(new-object Net.Sockets.TcpClient).Connect("10.45.23.109", 443)
This method works , but the output is not user-friendly. It means if there are no errors then it has access. Is there any way to check for success and display some message like » Port 443 is operational»?
essential
6181 gold badge6 silver badges19 bronze badges
asked Mar 5, 2012 at 11:44
SamselvaprabuSamselvaprabu
16.2k30 gold badges136 silver badges228 bronze badges
1
If you’re running Windows 8/Windows Server 2012 or newer, you can use the Test-NetConnection command in PowerShell.
Ex:
Test-NetConnection -Port 53 -ComputerName LON-DC1
EvilDr
8,45812 gold badges70 silver badges128 bronze badges
answered Sep 18, 2014 at 23:33
4
I improved Salselvaprabu’s answer in several ways:
- It is now a function — you can put in your powershell profile and use anytime you need
- It can accept host as hostname or as ip address
- No more exceptions if host or port unavaible — just text
Call it like this:
Test-Port example.com 999
Test-Port 192.168.0.1 80
function Test-Port($hostname, $port)
{
# This works no matter in which form we get $host - hostname or ip address
try {
$ip = [System.Net.Dns]::GetHostAddresses($hostname) |
select-object IPAddressToString -expandproperty IPAddressToString
if($ip.GetType().Name -eq "Object[]")
{
#If we have several ip's for that address, let's take first one
$ip = $ip[0]
}
} catch {
Write-Host "Possibly $hostname is wrong hostname or IP"
return
}
$t = New-Object Net.Sockets.TcpClient
# We use TryCatch to remove exception info from console if we can't connect
try
{
$t.Connect($ip,$port)
} catch {}
if($t.Connected)
{
$t.Close()
$msg = "Port $port is operational"
}
else
{
$msg = "Port $port on $ip is closed, "
$msg += "You may need to contact your IT team to open it. "
}
Write-Host $msg
}
answered Mar 21, 2014 at 8:02
mshutovmshutov
7771 gold badge5 silver badges13 bronze badges
Actually Shay levy’s answer is almost correct but i got an weird issue as i mentioned in his comment column. So i split the command into two lines and it works fine.
$Ipaddress= Read-Host "Enter the IP address:"
$Port= Read-host "Enter the port number to access:"
$t = New-Object Net.Sockets.TcpClient
$t.Connect($Ipaddress,$Port)
if($t.Connected)
{
"Port $Port is operational"
}
else
{
"Port $Port is closed, You may need to contact your IT team to open it. "
}
answered Mar 8, 2012 at 7:06
SamselvaprabuSamselvaprabu
16.2k30 gold badges136 silver badges228 bronze badges
You can check if the Connected property is set to $true and display a friendly message:
$t = New-Object Net.Sockets.TcpClient "10.45.23.109", 443
if($t.Connected)
{
"Port 443 is operational"
}
else
{
"..."
}
answered Mar 5, 2012 at 12:54
Shay LevyShay Levy
119k30 gold badges180 silver badges202 bronze badges
2
With the latest versions of PowerShell, there is a new cmdlet, Test-NetConnection.
This cmdlet lets you, in effect, ping a port, like this:
Test-NetConnection -ComputerName <remote server> -Port nnnn
I know this is an old question, but if you hit this page (as I did) looking for this information, this addition may be helpful!
answered Jul 18, 2017 at 19:41
Thomas LeeThomas Lee
1,1386 silver badges13 bronze badges
I tried to improve the suggestion from mshutov.
I added the option to use the output as an object.
function Test-Port($hostname, $port)
{
# This works no matter in which form we get $host - hostname or ip address
try {
$ip = [System.Net.Dns]::GetHostAddresses($hostname) |
select-object IPAddressToString -expandproperty IPAddressToString
if($ip.GetType().Name -eq "Object[]")
{
#If we have several ip's for that address, let's take first one
$ip = $ip[0]
}
} catch {
Write-Host "Possibly $hostname is wrong hostname or IP"
return
}
$t = New-Object Net.Sockets.TcpClient
# We use TryCatch to remove exception info from console if we can't connect
try
{
$t.Connect($ip,$port)
} catch {}
if($t.Connected)
{
$t.Close()
$object = [pscustomobject] @{
Hostname = $hostname
IP = $IP
TCPPort = $port
GetResponse = $True }
Write-Output $object
}
else
{
$object = [pscustomobject] @{
Computername = $IP
TCPPort = $port
GetResponse = $False }
Write-Output $object
}
Write-Host $msg
}
Brettski
18.9k15 gold badges74 silver badges93 bronze badges
answered Aug 4, 2014 at 9:56
If you are using older versions of Powershell where Test-NetConnection isn’t available, here is a one-liner for hostname «my.hostname» and port «123»:
$t = New-Object System.Net.Sockets.TcpClient 'my.hostname', 123; if($t.Connected) {"OK"}
Returns OK, or an error message.
answered Oct 19, 2017 at 21:54
David I.David I.
4,7193 gold badges25 silver badges34 bronze badges
Great answer by mshutov & Salselvaprabu. I needed something a little bit more robust, and that checked all IPAddresses that was provided instead of checking only the first one.
I also wanted to replicate some of the parameter names and functionality than the Test-Connection function.
This new function allows you to set a Count for the number of retries, and the Delay between each try. Enjoy!
function Test-Port {
[CmdletBinding()]
Param (
[string] $ComputerName,
[int] $Port,
[int] $Delay = 1,
[int] $Count = 3
)
function Test-TcpClient ($IPAddress, $Port) {
$TcpClient = New-Object Net.Sockets.TcpClient
Try { $TcpClient.Connect($IPAddress, $Port) } Catch {}
If ($TcpClient.Connected) { $TcpClient.Close(); Return $True }
Return $False
}
function Invoke-Test ($ComputerName, $Port) {
Try { [array]$IPAddress = [System.Net.Dns]::GetHostAddresses($ComputerName) | Select-Object -Expand IPAddressToString }
Catch { Return $False }
[array]$Results = $IPAddress | % { Test-TcpClient -IPAddress $_ -Port $Port }
If ($Results -contains $True) { Return $True } Else { Return $False }
}
for ($i = 1; ((Invoke-Test -ComputerName $ComputerName -Port $Port) -ne $True); $i++)
{
if ($i -ge $Count) {
Write-Warning "Timed out while waiting for port $Port to be open on $ComputerName!"
Return $false
}
Write-Warning "Port $Port not open, retrying..."
Sleep $Delay
}
Return $true
}
answered Oct 25, 2017 at 13:10
boiled this down to a one liner sets the variable «$port389Open» to True or false — its fast and easy to replicate for a list of ports
try{$socket = New-Object Net.Sockets.TcpClient($ipAddress,389);if($socket -eq $null){$Port389Open = $false}else{Port389Open = $true;$socket.close()}}catch{Port389Open = $false}
If you want ot go really crazy you can return the an entire array-
Function StdPorts($ip){
$rst = "" | select IP,Port547Open,Port135Open,Port3389Open,Port389Open,Port53Open
$rst.IP = $Ip
try{$socket = New-Object Net.Sockets.TcpClient($ip,389);if($socket -eq $null){$rst.Port389Open = $false}else{$rst.Port389Open = $true;$socket.close();$ipscore++}}catch{$rst.Port389Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,53);if($socket -eq $null){$rst.Port53Open = $false}else{$rst.Port53Open = $true;$socket.close();$ipscore++}}catch{$rst.Port53Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,3389);if($socket -eq $null){$rst.Port3389Open = $false}else{$rst.Port3389Open = $true;$socket.close();$ipscore++}}catch{$rst.Port3389Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,547);if($socket -eq $null){$rst.Port547Open = $false}else{$rst.Port547Open = $true;$socket.close();$ipscore++}}catch{$rst.Port547Open = $false}
try{$socket = New-Object Net.Sockets.TcpClient($ip,135);if($socket -eq $null){$rst.Port135Open = $false}else{$rst.Port135Open = $true;$socket.close();$SkipWMI = $False;$ipscore++}}catch{$rst.Port135Open = $false}
Return $rst
}
answered Apr 1, 2018 at 21:49
When scanning closed port it becomes unresponsive for long time. It seems to be quicker when resolving fqdn to ip like:
[System.Net.Dns]::GetHostAddresses("www.msn.com").IPAddressToString
Bhargav Rao
48.7k28 gold badges124 silver badges139 bronze badges
answered Apr 17, 2015 at 18:05
Powershell — Перечислите открытые порты UDP
Powershell — Перечислите открытые порты UDP
Хотите узнать, как перечислить открытые порты UDP с помощью Powershell? В этом учебнике мы покажем вам, как использовать Powershell для создания списка портов UDP в состоянии прослушивания на компьютере под управлением Windows.
• Windows 2012 R2
• Windows 2016
• Windows 2019
• Windows 10
Список оборудования
В следующем разделе представлен список оборудования, используемого для создания этого учебника.
Как Amazon Associate, я зарабатываю от квалификационных покупок.
Похожий учебник — PowerShell
На этой странице мы предлагаем быстрый доступ к списку учебников, связанных с PowerShell.
Учебник Powershell — Перечислите открытые порты UDP
Как Администратор, запустите новый запрос командной строки POWERSHELL.
Перечислите текущие соединения UDP.
Перечислите открытые порты UDP.
В нашем примере мы перечислили только порты UDP в состоянии прослушивания.
Дополнительно сортировать выход на основе номера порта UDP.
В нашем примере мы перечислили открытые порты UDP в состоянии прослушивания.
В нашем примере мы организовали выход команды на основе номера порта UDP.
Поздравляю! Вы можете перечислить открытые порты UDP с помощью Powershell.
Учебник Powershell — Перечислите соединения UDP с помощью скрипта
Как Администратор, запустите новый запрос командной строки POWERSHELL.
Перечислите все соединения по определенному IP-адресу.
Перечислите все соединения в порту UDP.
Перечислите название процесса и идентификатор локального порта UDP.
Поздравляю! Вы можете перечислить информацию о портах UDP с помощью скрипта Powershell.
VirtualCoin CISSP, PMP, CCNP, MCSE, LPIC22021-02-28T19:34:22-03:00
Related Posts
Page load link
Join Our Newsletter
Ok
Let’s dive into how to build a PowerShell test port tool that allows you to test open ports by port number and label.
To build a robust script that’s not going to fall over and die on half your servers it’s important to first make sure the prerequisites that exist in order for you to get your end result are met.
What are these prereqs? Prerequisites are services like FTP, HTTP, DCOM, WMI, WSMAN, etc. The connection you’re trying to make to a server typically depend on services like these.
There is a hierarchy of several layers of checks you can perform on your servers before attempting to make a connection depending on how anal you want to get.
For starters you’ve got the entire OSI stack to traverse on the network side. That’s not including services on the host system that you’re executing the script from and everything else on the remote host system.
One of the first tests you need to perform when querying a remote server is to check to ensure the appropriate network ports are open and accessible. Depending on the services running on the remote server depends on the ports you need to query.
I always used to either not even attempting to test port connections or fumbling around with finding that latest Test-Port script I had scavenged somewhere. Once I found it to figure out what ports I actually needed to a test ahead of time. Today was the final straw.
I needed to query a set of domain controllers before running some CIM queries against them. I went about my normal fumbling around and decided enough was enough and sat down and built my own, fully featured port testing script.
With help from this Technet script I managed to create pretty good pair of PowerShell functions that will not only allow you to test for open TCP and UDP ports but to test port groups by server role. No more Googling every time for what ports what service uses!
Granted, especially for Active Directory, the ports can vary by server OS, various services on a domain controller, etc. Feel free to tweak them as needed for your environment.
Here’s a screen host of a usage example:
As you can see, you can specify as many servers as you want and it will output a nice list of objects broken down by the service port group and the port for each computer. So far it’s come in very handy! I hope you get some use out of it like I have!
function Test-ServerRolePortGroup {
<#
.SYNOPSIS
This function tests for open TCP/UDP ports by server role.
.DESCRIPTION
This function tests for all the approprite TCP/UDP ports by server role so you don't have
to memorize or look up all of the ports that need to be tested for every time
you want to verify remote connectivity on a specific server role.
.NOTES
Link port references:
http://technet.microsoft.com/en-us/library/dd772723(v=ws.10).aspx
http://en.wikipedia.org/wiki/Server_Message_Block
http://technet.microsoft.com/en-us/library/cc940063.aspx
.PARAMETER Computername
One or more remote, comma-separated computer names
.PARAMETER ServerRole
The services on the computer that you'd like to find open ports for. This can be
common services like WinRm, Smb, Dns, Active Directory and NetBIOS
.EXAMPLE
PS> Test-ServerRolePortGroup -Computername 'LABDC','LABDC2' -ServerRole NetBIOS,WinRm,Dns
This example tests the network ports necessary for NetBIOS, WinRm and Dns
to operate on the servers LABDC and LABDC2.
#>
[CmdletBinding()]
[OutputType([System.Management.Automation.PSCustomObject])]
param (
[Parameter(Mandatory)]
[ValidateScript({ Test-Connection -ComputerName $_ -Count 1 -Quiet})]
[string[]]$Computername,
[Parameter(Mandatory)]
[ValidateSet('WinRm','Smb','Dns','ActiveDirectoryGeneral','ActiveDirectoryGlobalCatalog','NetBios')]
[string[]]$ServerRole
)
begin {
$PortGroups = @{
'WinRm' = @{ 'TCP' = 5985}
'Smb' = @{ 'TCP' = 445; 'UDP' = 445 }
'Dns' = @{ 'TCP' = 53; 'UDP' = 53 }
'ActiveDirectoryGeneral' = @{ 'TCP' = 25, 88, 389, 464, 636, 5722, 9389; 'UDP' = 88,123,389,464 }
'ActiveDirectoryGlobalCatalog' = @{ 'TCP' = 3268, 3269 }
'NetBios' = @{ 'TCP' = 135, 137, 138, 139; 'UDP' = 137,138,139 }
}
}
process {
foreach ($Computer in $Computername) {
Write-Verbose "Beginning port tests on computer '$Computer'"
try {
$TestPortGroups = $PortGroups.GetEnumerator() | where { $ServerRole -contains $_.Key }
Write-Verbose "Found '$($TestPortGroups.Count)' port group(s) to test"
foreach ($PortGroup in $TestPortGroups) {
$PortGroupName = $PortGroup.Key
$PortGroupValues = $PortGroup.Value
foreach ($Value in $PortGroupValues.GetEnumerator()) {
$Protocol = $Value.Key
$Ports = $Value.Value
$TestResult = Test-Port -ComputerName $Computer -Protocol $Protocol -Port $Ports
$TestResult | Add-Member -MemberType 'NoteProperty' -Name 'PortSet' -Value $PortGroupName
$TestResult
}
}
} catch {
Write-Verbose "$($MyInvocation.MyCommand.Name) - Computer: $Computer - Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)"
$false
}
}
}
}
function Test-Port {
<#
.SYNOPSIS
This function tests for open TCP/UDP ports.
.DESCRIPTION
This function tests any TCP/UDP port to see if it's open or closed.
.NOTES
Known Issue: If this function is called within 10-20 consecutively on the same port
and computer, the UDP port check will output $false when it can be
$true. I haven't figured out why it does this.
.PARAMETER Computername
One or more remote, comma-separated computer names
.PARAMETER Port
One or more comma-separated port numbers you'd like to test.
.PARAMETER Protocol
The protocol (UDP or TCP) that you'll be testing
.PARAMETER TcpTimeout
The number of milliseconds that the function will wait until declaring
the TCP port closed.
.PARAMETER
The number of millieconds that the function will wait until declaring
the UDP port closed.
.EXAMPLE
PS> Test-Port -Computername 'LABDC','LABDC2' -Protocol TCP 80,443
This example tests the TCP network ports 80 and 443 on both the LABDC
and LABDC2 servers.
#>
[CmdletBinding(DefaultParameterSetName='TCP')]
[OutputType([System.Management.Automation.PSCustomObject])]
param (
[Parameter(Mandatory)]
[string[]]$ComputerName,
[Parameter(Mandatory)]
[int[]]$Port,
[Parameter(Mandatory)]
[ValidateSet('TCP', 'UDP')]
[string]$Protocol,
[Parameter(ParameterSetName='TCP')]
[int]$TcpTimeout = 1000,
[Parameter(ParameterSetName = 'UDP')]
[int]$UdpTimeout = 1000
)
process {
foreach ($Computer in $ComputerName) {
foreach ($Portx in $Port) {
$Output = @{ 'Computername' = $Computer; 'Port' = $Portx; 'Protocol' = $Protocol; 'Result' = '' }
Write-Verbose "$($MyInvocation.MyCommand.Name) - Beginning port test on '$Computer' on port '$Protocol<code>:$Portx'"
if ($Protocol -eq 'TCP') {
$TcpClient = New-Object System.Net.Sockets.TcpClient
$Connect = $TcpClient.BeginConnect($Computer, $Portx, $null, $null)
$Wait = $Connect.AsyncWaitHandle.WaitOne($TcpTimeout, $false)
if (!$Wait) {
$TcpClient.Close()
Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' failed port test on port '$Protocol</code>:$Portx'"
$Output.Result = $false
} else {
$TcpClient.EndConnect($Connect)
$TcpClient.Close()
Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' passed port test on port '$Protocol<code>:$Portx'"
$Output.Result = $true
}
$TcpClient.Close()
$TcpClient.Dispose()
} elseif ($Protocol -eq 'UDP') {
$UdpClient = New-Object System.Net.Sockets.UdpClient
$UdpClient.Client.ReceiveTimeout = $UdpTimeout
$UdpClient.Connect($Computer, $Portx)
Write-Verbose "$($MyInvocation.MyCommand.Name) - Sending UDP message to computer '$Computer' on port '$Portx'"
$a = new-object system.text.asciiencoding
$byte = $a.GetBytes("$(Get-Date)")
[void]$UdpClient.Send($byte, $byte.length)
#IPEndPoint object will allow us to read datagrams sent from any source.
Write-Verbose "$($MyInvocation.MyCommand.Name) - Creating remote endpoint"
$remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any, 0)
try {
#Blocks until a message returns on this socket from a remote host.
Write-Verbose "$($MyInvocation.MyCommand.Name) - Waiting for message return"
$receivebytes = $UdpClient.Receive([ref]$remoteendpoint)
[string]$returndata = $a.GetString($receivebytes)
If ($returndata) {
Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' passed port test on port '$Protocol</code>:$Portx'"
$Output.Result = $true
}
} catch {
Write-Verbose "$($MyInvocation.MyCommand.Name) - '$Computer' failed port test on port '$Protocol`:$Portx' with error '$($_.Exception.Message)'"
$Output.Result = $false
}
$UdpClient.Close()
$UdpClient.Dispose()
}
[pscustomobject]$Output
}
}
}
}