The Surly Admin

Father, husband, IT Pro, cancer survivor

Using Powershell as a Telnet Client

One of the things I’ve been meaning to do is create a script to telnet to my various network devices and download the configuration as a poor man’s backup.  Well, recently this post came across Spiceworks and I felt it was time to take a deeper look at how to do this.

What to do?

My initial thought was to use Putty or Plink to script the connection, but to be honest I couldn’t find any good documentation for doing it.  Next I tried Telnet.exe which used to come with Windows but isn’t there by default anymore.  Turns out it’s pretty easy to go into Features and add it, but scripting it also turned out to be less than ideal and besides, I really like my scripts to not require anything to be installed in order to run.  I guess I’m gonna have to break down and see if there is a .NET way of doing this.  Not my favorite method as I find the .NET stuff pretty difficult to work with–which explains why I think the learning curve on Powershell ramps back up as you get more advanced–but sometimes you just have to go there.

As 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 needs.

What We’re Doing

I’ve said it before, it’s always a good idea to have a clear idea of what you want the script to accomplish.  How you get there, and the different capabilities you can put in can come later but it’s really important to know exactly what you want to get done.

With this script I want to connect to a device, display the configuration and save the results to a file.  Since I have a few devices that I want to do this with I want to be able to loop through the many devices.  The problem here is that the devices are different types, Extreme Network switches, Dell PowerConnect switches and a Cisco ASA firewall.  That means the script has to be able to accept commands from a parameter.  That means we have to take Lee’s snippet of code and adapt it to our needs.

Doing the commands should be easy enough, we can just make an array and use ForEach to loop through the array.  So let’s get started:

$Socket = New-Object System.Net.Sockets.TcpClient($RemoteHost, $Port)
If ($Socket)
{  $Stream = $Socket.GetStream()
   $Writer = New-Object System.IO.StreamWriter($Stream)
   $Buffer = New-Object System.Byte[] 1024
   $Encoding = New-Object System.Text.AsciiEncoding
ForEach ($Command in $Commands)
   {  $Writer.WriteLine($Command)
      $Writer.Flush()
   }

Simple so far, we just want to connect to the host and do a quick check if we succeeded or not–if we didn’t than $Socket will be $null.  After that we setup our variables to read the stream from the TCP socket and then loop through our commands and send them over.  This is where the first problem came in.  During testing I found the script was running much faster than my remote device, so text was being sent while the device wasn’t listening and commands just got lost.  That means we gotta slow down.  To do this, I simply added a Start-Sleep command after each command.  I decided to make the time you wait between commands a parameter so you can adjust the script to match the device–assuming some devices will be slower or faster than others.  And you’ll have to adjust this for every device you have because they all respond differently.  If you find your output is incomplete just bump $WaitTime up another 500 milliseconds and try again.

Typically the last command in our command stream is going to be the longest command–like Show Run on Cisco devices, or Show Config on Extreme Network switches–so I had to add another wait after all of the commands are sent to make sure that last command has time to finish.  Since I defined a $WaitTime variable in parameters I just took that time and multiplied it by 4 to make sure I waited plenty of time.

After that we just read the Socket stream and save the results to a variable:

Start-Sleep -Milliseconds ($WaitTime * 4)
$Result = ""
While($Stream.DataAvailable)
{  $Read = $Stream.Read($Buffer, 0, 1024)
   $Result += ($Encoding.GetString($Buffer, 0, $Read))
}

After this it’s a simple matter of piping the $Results variable to Out-File to save it.  The trick was how do I run this same thing for all of my devices?  The first thought was to simply make scheduled tasks and make a script for each device.  But to set up all those scheduled tasks is a lot of work, unless I decide to script it!  I’ll save that for another day!

So how do we repeat the same code in a script while only writing it once?  Sounds an awful lot like a function, don’t you think?  So I wrap the entire script in a Function {} block and now at the bottom of the script I can call the function, put my specific parameters in and get all of my devices in one simple script.  I decided to call the function Get-Telnet.  Here are some examples of my devices:

Get-Telnet -RemoteHost "10.10.10.10" -OutputPath "\\server\share\hqswitches.txt" -Commands "username","password","disable clipaging","sh config"

This is for my Extreme Networks switch and I’ll be using the default port and wait time (1000 milliseconds).  I pass the username and password first, than use “disable clipaging” to make the Extreme Switch scroll the entire contents of “Show Config” without pausing.

Get-Telnet -RemoteHost "10.10.10.11" -Commands "username","password","terminal datadump","show run" -OutputPath "\\server\share\DellHQswitches.txt" -WaitTime 2000

And here’s the command line for my Dell switches.  Slightly different commands, of course, and I had to adjust the $WaitTime up because the Dell switch was a little slower to respond than the Extreme Switch.

Get-Telnet -RemoteHost "10.10.10.1" -Commands "admin","password","terminal pager 0","show run" -OutputPath "\\server\share\CiscoFirewall.txt"

And last, here’s how to do it with a Cisco ASA firewall.  All of these are assuming you’ve setup the devices to allow Telnet communications, of course.  Now I just string these lines together in a single script and schedule it to run and I have a nice little backup of my different devices and adding more is as simple as setting up a new line.

As always, I’ve posted the source code up on Spiceworks, you’ll just have to adjust the PARAM section of the Function to match the default settings you want to use.

Source Code For Get-Telnet

Advertisement

April 4, 2013 - Posted by | PowerShell | , , ,

30 Comments »

  1. Hi, can you tell me how to add newline to output after each command (my telnet output echoes in the same line where i enter command)?

    Comment by Dusan Tomic | October 2, 2013 | Reply

    • That’s a tough one as the script relies on the output for the formatting… you could try replacing this:
      ForEach ($Command in $Commands)
      { $Writer.WriteLine($Command)
      $Writer.Flush()
      Start-Sleep -Milliseconds $WaitTime
      }

      With
      ForEach ($Command in $Commands)
      { $Writer.WriteLine(“`n$Command`n”)
      $Writer.Flush()
      Start-Sleep -Milliseconds $WaitTime
      }

      `n is a carriage return, so we’re essentially surrounding the command with “enter”‘s… But beyond that I’m not sure what you could do!

      Comment by Martin9700 | October 4, 2013 | Reply

  2. […] Grundlage des Skripts kommt hier das Telnet-Skript von Martin Pugh zum Einsatz. Mit Hilfe dieser Funktion kann eine Verbindung über Powershell zu […]

    Pingback by groeby.net | Backup der Switchkonfiguration per Powershell | February 6, 2014 | Reply

  3. Reblogged this on Harshal's Blogs.

    Comment by harshal20 | April 3, 2014 | Reply

  4. Hi,
    Great script, I’ trying to use it with the script by groeby.net. The problem is, that some of my switches (different manufacturers and telnet behavior when saving running config or copying over tftp) act weird.
    What I like to see: wait for output, which will also avoid that ‘fire and forget waitcycle’ 😉
    Since I’m just starting to wrap my head around powershell I don’t know how to accomplish this 🙂

    Or is it easier to do it with spiceworks, which I tested two years ago?

    Comment by Matthias | July 14, 2014 | Reply

    • Unless it’s specifically written for a particular device, no Telnet client waits for prompt, you can pretty much type anytime, but things are scrolling by so fast it’s hard to tell. You could certainly write PowerShell to wait for a certain set of characters before accepting input–this would correspond with whatever your particular device displays for it’s prompt.

      Comment by Martin9700 | July 14, 2014 | Reply

      • Yeah, that’s the problem, my 5524 behave totally different than my 7024 and my Edge-Core switches. Well.. I think it’s easier to use one of unix machines and some expect 😉
        Thanks for your time 🙂

        Comment by Matthias | July 14, 2014

  5. I left a reply here a few days ago, and assumed it was awaiting moderator approval. Did it get lost?

    Comment by Scott Wertz | November 2, 2014 | Reply

    • Hi Scott, nothing pending, sorry I lost your first comment!

      Comment by Martin9700 | November 2, 2014 | Reply

  6. I can confirm code above works….for cisco IOS router.
    However, I’m trying to issue telnet commands to Cisco wireless lan controller, and run into following error:in output.
    suggestions welcome

    (Cisco Controller)
    User: admin
    Password:Raw mode will not be supported, Closing connection.

    Comment by 16again | February 4, 2015 | Reply

  7. […] : communiquer avec telnet dans un script PowerShell et envoyer les commandes. Merci à Martin9700 Using Powershell as a Telnet Client Get-Telnet – Telnet to a device and issue […]

    Pingback by CommandeLine Partie 1 | Blog d'un consultant BI | June 10, 2015 | Reply

  8. Hi,

    Although the script works great for our cisco environment it doesn’t work for our Alcatel Telephony server.

    It only returns ??↑?? ??#??’ and nothing after that. Any idea?

    Comment by TheSottos | January 8, 2016 | Reply

    • No, unfortunately. It’s probably an emulation type problem. You could take a look at the .Net object and see if there’s any settings you can try.

      Comment by Martin9700 | January 8, 2016 | Reply

      • Any comment about the questions marks, I have the same issue trying to telnet Cisco Telepresence devices and not found any solution.

        Comment by Roberto Hernandez | February 16, 2016

      • Roberto, I really don’t know. I don’t have access to these types of devices so can’t test anything. As I mentioned above it looks like an emulation issue so I would suggest checking out the System.Net.Sockets.Tcpclient class and seeing if there’s any settings you could use.

        Comment by Martin9700 | February 16, 2016

    • @TheSottos Did you ever find an explanation/solution for the strange output you received from your device ? I have the same problem telnetting to a Synology NAS: getting ??%??&???? ??#??’??$

      Comment by PatrickE | December 14, 2016 | Reply

      • No, sorry

        Comment by Martin9700 | December 14, 2016

      • Thanks (hopefully TheSottos did and will still respond). I noticed using putty that the device (Synology DS416) responds with the same rubbish characters when raw connection type is selected, but readable chars when Telnet or SSH connection type is selected. Am investigating this further now, will post if I find anything useful.

        Comment by PatrickE | December 14, 2016

  9. […] Using Powershell as a Telnet Client […]

    Pingback by Linkdump: Scripted telnet via Powershell – PlayfulFlower | February 29, 2016 | Reply

  10. @TheSottos Did you ever find an explanation/solution for the strange output you received from your device ? I have the same problem telnetting to a Synology NAS: getting ??%??&???? ??#??’??$

    Comment by PatrickE | December 14, 2016 | Reply

  11. is there a way of making this by pass interactive commands…. if I try and do a “Sh run” on certain cisco equipment it wants me to obviously press a button to move on, which means my output doesn’t come out as fully expected because a good portion is missing.

    Comment by chris armitage | March 7, 2017 | Reply

    • No, not really. You’ll need to configure the device to show the entire configuration when you “sh run”

      Comment by Martin9700 | March 7, 2017 | Reply

      • damn…I found this on line (http://www.serveradventures.com/the-adventures/get-ciscoconfig-using-powershell-to-backup-cisco-configurations) and it works until I change it to telnet instead of using ssh. The issue I’ve got is we have a lot of switches and all differently configured (some with ssh some with out etc) so a hybrid of your script and the other one would be perfect.

        The issue with the other script is it don’t seem to take UN and PW when using telnet no matter how I try and input in but it does show the entire config, because it can use the -batch switch when using Plink. Where as yours takes the UN and PW but doesn’t show the entire config :-S

        Comment by chris armitage | March 7, 2017

  12. Hello.

    I’m trying to fetch information from a Dell firewall, but the message appears:

    New-Object: Exception calling “.ctor” with “2” argument (s): “No connection could be made because the target machine actually refused it …

    Do I need any DLLs?

    Using PLINK I can see the information I need manually, but when I try to automate it, a SHELL error message appears.

    I am looking for alternatives to be able to extract the information to display in the command itself or in a TXT file.

    Thank you.

    Comment by Sandro | May 11, 2017 | Reply

  13. […] code, vous manquez le TCP en entrée lors de l'attente pour l'entrée de l'utilisateur. Aussi cette une est mis en œuvre à l'aide de […]

    Pingback by .net - Comment se connecter à un socket tcp avec powershell pour envoyer et recevoir des données? | April 19, 2019 | Reply

  14. […] en el código, olvida el TCP de entrada mientras se espera la entrada del usuario. También este uno se implementa el uso de […]

    Pingback by .net - Cómo conectarse a la conexión tcp con powershell para enviar y recibir datos? | September 14, 2019 | Reply

  15. Hey Martin, I’m trying to use this to read a blob of binary data from my weather station, but I’m seeing the occasional difference in a byte or two compared to what WireShark reports, and I’m thinking it’s the encoding changing some of the values.

    I can’t figure out how to modify this to save the raw data. Is that something really obvious I’m missing?

    Thanks.

    Comment by Greig Sheridan | February 10, 2020 | Reply

    • Sorted it! $Buffer held what I wanted all along.

      Comment by Greig Sheridan | February 12, 2020 | Reply


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: