39

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
  • 648
  • 1
  • 7
  • 19
Samselvaprabu
  • 16,830
  • 32
  • 144
  • 230

10 Answers10

67

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,943
  • 14
  • 73
  • 133
SimonOzturk
  • 791
  • 1
  • 5
  • 3
  • 3
    Test-NetConnection only works on Windows 8.x and Server 2012R2 and newer. – dragon788 Jan 06 '17 at 18:03
  • Down vote as `Test-NetConnection` isn't available until PS 5. – Brettski Sep 08 '17 at 21:04
  • @Brettski Your comment is flat wrong. Just tested on a Windows Server 2012 machine with PS4. It is, however, part of the [NetTCPIP module](https://learn.microsoft.com/en-us/powershell/module/nettcpip/?view=win10-ps), which is not available on Windows 7 and Windows Server 2008 R2 and lower. – jpmc26 Nov 10 '17 at 23:45
  • @jpmc26 Ah you're right it's a PowerShell 4 cmdlet. Mistakes happen. Down-vote removed. – Brettski Nov 12 '17 at 14:12
44

I improved Salselvaprabu's answer in several ways:

  1. It is now a function - you can put in your powershell profile and use anytime you need
  2. It can accept host as hostname or as ip address
  3. 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 Try\Catch 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
}
mshutov
  • 792
  • 1
  • 5
  • 14
16

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. "
    }
Samselvaprabu
  • 16,830
  • 32
  • 144
  • 230
14

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
    {
        "..."
    }
Shay Levy
  • 121,444
  • 32
  • 184
  • 206
  • Buddy , I am facing weird issue with above solution. For example. I first used port 443 , it failed and displayed else part string. then I gave the port number which has access ( 80 ). It displayed if part string. again i changed the port number to 443 and it displayed if part string. ( it should have displayed else string) – Samselvaprabu Mar 06 '12 at 07:03
  • And this is enough to get a true/false response `(New-Object Net.Sockets.TcpClient "10.45.23.109", 443).Connected` – ndemou Jun 27 '19 at 11:03
7

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!

Thomas Lee
  • 1,158
  • 6
  • 13
4

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 Try\Catch 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
  • 19,351
  • 15
  • 74
  • 97
Hilbert
  • 41
  • 1
4

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.

David I.
  • 4,747
  • 3
  • 26
  • 34
0

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

}
Marc Kellerman
  • 466
  • 3
  • 10
0

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
}
-1

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
  • 50,140
  • 28
  • 121
  • 140
uzjsme
  • 1
  • 1