Help! Telnet not installed!

If you’re a system administrator the following has probably happened to you: you’re trying to troubleshoot a connection issue to a service in the environment and you want to test if a specific port is open on the destination machine. Being the veteran that you are you immediately turn to the trusted telnet command only to receive the dredded Telnet is not recognized as a command… error notifying you the client is not installed on the local system.

So now what? Sure you can simply install the client and go back to your old ways but there’s a better alternative these days that requires no installation: the PowerShell command Test-NetConnection.
(not available on Windows 7 but we’ll fix that later on)

To test port connectivity like you would using telnet you simply open a powershell console and type:

Test-NetConnection -ComputerName www.peppercrew.nl -Port 443

This will perform a ping and tests port connectivity, giving you the following output:

ComputerName           : www.peppercrew.nl
RemoteAddress : 104.207.253.58
RemotePort : 443
InterfaceAlias : LAN01
SourceAddress : 10.100.1.12
PingSucceeded : True
PingReplyDetails (RTT) : 157 ms
TcpTestSucceeded : True

As you can see, the ping succeeded and so did the TcpTest on port 443. You can also use the InformationLevel parameter with value Quiet if you only need a boolean (true/false) answer to your request. This is recommended practice when using this command in a script because it is much faster. The Test-NetConnection command is even faster than the Test-Connection command. It’s also more versatile: it can also be used for route tracing and route selection diagnostics.

If you’re environment is a bit behind and you’re source computer is still on Windows 7 or Server 2018 R2 then you’re out of luck: the Test-NetConnection command is not available on these operating systems even when you have PowerShell 5.1 installed. There’s still one alternative that does not require installing telnet! Just open you PowerShell console and type:

[System.Net.Sockets.TcpClient]::new('www.peppercrew.nl',443)

This syntax is a little more difficult to remember because it’s dotnet, but it works like a charm. This command gives you the following output:

Client              : System.Net.Sockets.Socket
Available : 0
Connected : True
ExclusiveAddressUse : False
ReceiveBufferSize : 65536
SendBufferSize : 64512
ReceiveTimeout : 0
SendTimeout : 0
LingerState : System.Net.Sockets.LingerOption
NoDelay : False

As you can see by the value in the Connected property the port connection succeeded. I’ve used this method to create a Windows 7 version of the Test-NetConnection commandIt works very much the same as it’s Windows 8+ counterpart (no route tracing though). You can add ports you test regularly to the CommonTCPPort parameter list in the begin block (you have to add them to the validation set on the parameter as well). Hopefully it will be helpful for some of you.

<#
.Synopsis
   Displays diagnostic information for a connection.
.DESCRIPTION
   The Test-NetConnection cmdlet displays diagnostic information for a connection. 
   It supports ping test and TCP test. Depending on the input parameters, the output 
   can include the DNS lookup results, a list of IP interfaces and/or confirmation 
   of connection establishment.
.EXAMPLE
   Test-NetConnection
   Test internet connectivity (port 80)
.EXAMPLE
   Test-NetConnection -CommonTCPPort HTTPS
   Test internet connectivity (port 443)
.EXAMPLE
   Test-NetConnection -ComputerName SRV-001
   Test connection to computer SRV-001 (ping only)
.EXAMPLE
   Test-NetConnection -ComputerName SRV-001 -Port 3193
   Test port connection to computer SRV-001 using port 3193 (Detailed)
.EXAMPLE
   Test-NetConnection -ComputerName 10.100.10.15 -CommonTCPPort WINRM -InformationLevel Quiet
   Test port connection on ip address 10.100.10.15 on the Windows Remote Management port (True/False)
#>
function Test-NetConnection 
{
    [CmdletBinding(DefaultParameterSetName='Port')]
    [Alias('telnet','tnc')]
    Param
    (
        # Specifies the Domain Name System (DNS) name or IP address of the target computer that runs the Dynamic Host Configuration Protocol (DHCP) server service.
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [Alias('Name','PSComputerName','VMName')]
        [string]
        $ComputerName = 'internetbeacon.msedge.net',

        # Specifies the TCP port number on the remote computer. The cmdlet uses this port number to test connectivity to the remote computer.
        [Parameter(ParameterSetName='Port',
                   Position=1)]
        [int]
        $Port,

        # Specifies the common service TCP port number.
        [Parameter(Mandatory=$true,
                   ParameterSetName='CommonPort',
                   Position=1)]
        [ValidateSet('SMB','HTTP','HTTPS','RDP','WINRM')]
        [string]
        $CommonTCPPort,

        # Specifies the information level.
        [Parameter(Position=2)]
        [ValidateSet('Detailed','Quiet')]
        [string]
        $InformationLevel = 'Detailed'
    )

    Begin
    {
        If ($PSBoundParameters['CommonTCPPort'])
        {
            switch ($CommonTCPPort)
            {
                SMB   {$Port = 445}
                HTTP  {$Port = 80}
                HTTPS {$Port = 443}
                RDP   {$Port = 3389}
                WINRM {$Port = 5985}
            }
        }
        If (!$PSBoundParameters['ComputerName'] -and !$PSBoundParameters['Port'])
        {
            $Port = 80
        }
    }
    Process
    {
        try
        {
            $IPDestination = [System.Net.Dns]::GetHostEntry($ComputerName).AddressList.IPAddressToString
        }
        catch
        {
            Write-Warning "Ping to $ComputerName failed"
        }
        If (!($PSBoundParameters['Port'] -and $InformationLevel -eq 'Quiet'))
        {
            try
            {
                $Ping = [System.Net.NetworkInformation.Ping]::new().Send($ComputerName)
                $PingSuccess = $Ping.Status -eq 'Success'
            }
            catch{
                $PingSuccess = $false
            }
            If (!$PingSuccess)
            {
                Write-Warning "Ping to $ComputerName failed"
            }
        }
        If ($Port)
        {
            Try
            {
                $TcpClient = [System.Net.Sockets.TcpClient]::new($IPDestination,$Port)
            }
            catch{}
            If ($TcpClient)
            {
                $Connected = $TcpClient.Connected
            }
            else
            {
                $Connected = $false
            }
            If (!$Connected)
            {
                Write-Warning "TCP connect to $ComputerName`:$Port failed"
            }
        }
        switch ($InformationLevel)
        {
            Quiet    {
                If ($PSBoundParameters['Port'] -or $PSBoundParameters['CommonTCPPort'])
                {
                    return $Connected
                }
                else
                {
                    return $PingSuccess
                }
            }
            Detailed {
                $Adapter = Get-WmiObject Win32_NetworkAdapter -Filter "PhysicalAdapter='True' AND NetEnabled='True'"
                If ($Adapter.Count -gt 1)
                {
                    (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage").Bind.foreach({
                        $GUID = $_.Split('\')[2]
                        If ($GUID -in $Adapter.GUID)
                        {
                            $Adapter = $Adapter.Where({$_.GUID -eq $GUID})
                            Break
                        }
                    })
                }
                $AdapterConfig = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter "Index = $($Adapter.DeviceID)"
                [pscustomobject]@{
                    ComputerName             = $ComputerName
                    RemoteAddress            = $IPDestination
                    PingSucceeded            = $PingSuccess
                    'PingReplyDetails (RTT)' = $Ping.RoundtripTime.ToString() + ' ms'
                    RemotePort               = $Port
                    InterfaceAlias           = $Adapter.NetConnectionID
                    InterfaceIndex           = $Adapter.InterfaceIndex
                    InterfaceDescription     = $Adapter.Description
                    NetAdapter               = $Adapter
                    SourceAddress            = $AdapterConfig.IPAddress
                    TcpTestSucceeded         = $Connected
                }
            }
        }
    }
}
0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *