Replacing Telnet.exe (now removed from Vista)

Probably the most useful network tool on any operating system is Telnet.  Not for connecting to Telnet servers, of course, as the Telnet protocol is about as insecure as they come.  Instead, it’s useful for debugging connection problems with arbitrary ports and arbitrary protocols.

Debugging an HTTP problem?  You can Telnet into port 80 to help you resolve it.
Debugging a mail retrieval issue?  You can Telnet into port 110 to help you resolve it.
Debugging a mail sending issue?  You can Telnet into port 25 to help you resolve it.
<etc>

Unfortunately, this workhorse was removed from Vista’s default installation.  Here’s a simple PowerShell replacement script.  It’s great for debugging, but useless (of course) for terminal emulation:

 

## Connect-Computer.ps1
## Interact with a service on a remote TCP port
param(
    [string] $remoteHost = "localhost",
    [int] $port = 80
     )

## Open the socket, and connect to the computer on the specified port
write-host "Connecting to $remoteHost on port $port"
$socket = new-object System.Net.Sockets.TcpClient($remoteHost, $port)
if($socket -eq $null) { return; }

write-host "Connected.  Press ^D followed by [ENTER] to exit.`n"

$stream = $socket.GetStream()
$writer = new-object System.IO.StreamWriter($stream)

$buffer = new-object System.Byte[] 1024
$encoding = new-object System.Text.AsciiEncoding

while($true)
{
   ## Allow data to buffer for a bit
   start-sleep -m 500

   ## Read all the data available from the stream, writing it to the
   ## screen when done.
   while($stream.DataAvailable) 
   { 
      $read = $stream.Read($buffer, 01024)   
      write-host -n ($encoding.GetString($buffer, 0, $read)) 
   }

   ## Read the user's command, quitting if they hit ^D
   $command = read-host
   if($command -eq ([char4)) { break; }
 
   ## Write their command to the remote host     
   $writer.WriteLine($command)
   $writer.Flush()
}

## Close the streams
$writer.Close()
$stream.Close()

11 Responses to “Replacing Telnet.exe (now removed from Vista)”

  1. Steve Maine writes:

    Vista has both a Telnet client and a Telnet server built-in. They’re just off by default.

    You can find them in the "Turn Windows Features On or Off" dialog inside the Programs control panel.

  2. Stéphane de Luca writes:

    Hi,

    I wrote for myself a Web service to telnet very simply any server. As t proved to be very useful, I propose it to everyone on the web: http://browseas.com/telnet.php

  3. Lee writes:

    Nice job! It hung when I tried to use any interactive protocols, though 🙂

  4. L. Dopa writes:

    Well, AbsoluteTelnet is indeed a good one, but it’s not commandline-based and it’s not free.
    You might wanna consider PuTTY instead, or just enable it again in Vista …

  5. PT writes:

    start – run – "start /w ocsetup TelnetClient"
    voila! telnet installed, problem solved.

  6. Cool PowerShell Script Replicates Telnet « Brian Reiter's Thoughtful Code writes:

    […] 8, 2011 by Brian Reiter Leave a Comment Lee Holmes has a cool script to reproduce telnet-like functionality via the TcpClient object in […]

  7. Using Powershell as a Telnet Client « The Surly Admin writes:

    […] always, Google is our friend and I soon found this little snippet of code from Lee Holmes.  It’s a little rough, but we can definitely modify it to our […]

  8. Leo writes:

    Has anyone run in to the problem where the encoding was improperly handled?

    I have used this code to connect via a telnet session and it came out as
    ???? ??#??’

    it should say username. I attempted to use all the encoding that Powershell has available in the “system.text.”But they all come out with different windings and garbage text. Any suggestions?

  9. ivarson writes:

    @Leo, have the samme problem. Ive set up ncat spawning a cmd.exe on my local 23-port, and then this nifty scripts runs good, but not against my FC-switches (showing the exact same prompt as yours)

  10. Kristian writes:

    I wrote up a version of this that’s in a single class, for anyone who prefers to play the game that way. It always feels better to be object oriented than purely functional.

    class TelnetConnection {
    [String]$RemoteHost
    [int32]$Port
    [array]$Log
    $Socket
    $Stream
    $Writer
    $Buffer
    $Encoding

    TelnetConnection ([String]$RemoteHost, [int32]$Port) {
    Try {
    $this.RemoteHost = $RemoteHost
    $this.Port = $Port
    $this.Socket = New-Object System.Net.Sockets.TcpClient($this.RemoteHost, $this.Port) -ErrorAction Stop
    $this.Stream = $this.Socket.GetStream()
    $this.Writer = New-Object System.IO.StreamWriter($this.Stream)
    $this.Buffer = New-Object System.Byte[] 1024
    $this.Encoding = New-Object System.Text.AsciiEncoding
    } Catch [System.Management.Automation.MethodInvocationException] {
    Write-Host “There was an error connecting to the remote site:”
    Write-Host $Error[0].Exception
    pause
    exit
    } Catch {
    write-host “Breaking due to error”
    write-host $Error[0].Exception
    pause
    exit
    }
    }

    #Returns the current start of the connection.
    #$True if connected, $False if not.

    [Boolean] GetConnection() {
    Return $this.Socket.Connected
    }

    #Sends individual commands to the stream using the writer.
    #Retrieves the results of the commands 1 second after they have been sent.
    #Returns the results of the commands, and writes them to the log.

    [String] SendCommand([String]$Command) {
    $this.Writer.WriteLine($Command)
    $this.Writer.Flush()
    Start-Sleep -Milliseconds 1000
    if ($this.Stream.DataAvailable) {
    $Read = $this.Stream.Read($this.Buffer, 0, 1024)
    $this.Log += ($this.Encoding.GetString($this.Buffer, 0, $Read))
    Return ($this.Encoding.GetString($this.Buffer, 0, $Read))
    } else {
    Return “No response to command”
    }
    }

    #Returns any pending command results. Used if the results of a command are bigger than the buffer.

    [String] GetOutput() {
    $Read = $this.Stream.Read($this.Buffer, 0, 1024)
    $this.Log += ($this.Encoding.GetString($this.Buffer, 0, $Read))
    Return ($this.Encoding.GetString($this.Buffer, 0, $Read))
    }

    #Gracefully closes the connection by closing the writer, the stream, and the socket.
    #Returns $True if successful, $False if not.

    [Boolean] KillConnection(){
    $this.Writer.Close()
    $this.Stream.Close()
    $this.Socket.Close()
    if ($this.Socket.Connected -eq $False -and $this.Stream.CanWrite -eq $False -and $this.Writer.BaseStream -eq $null) {
    Return $True
    } else {
    Return $False
    }
    }
    }

  11. MSM writes:

    I want to say thanks for this PowerShell code example. I recently learned that whois data can be queried via telnet over port 43, and I was interested to see if I could make a whois function in PowerShell which takes advantage of this. Your code has helped me bootstrap that effort. As much as I appreciate the Sysinternals tools, the whois.exe behaves badly on my Windows 10 PC with Godaddy domains and I wanted something I could integrate seamlessly into other scripts I am writing.

Leave a Reply