How to maintain a 'conversation' with an SSH session?

Nov 8, 2013 at 11:54 PM
I know this sounds weird. In the examples I can find, a send command & get results type of session is just that: Connect, create SshShell, WriteLine, ReadLine, done.

But this isn't what a real session is like when you need to drill down the command tree, then gather the results of just the last/current command you issued. You can't drill down a few levels in, say, a Cisco router with, for example, enable, enablePass, conf t, int 123, etc. by disconnecting and reconnecting for every command.

And I'm noticing that using Expect(), which is an amazing and extremely useful function, does NOT show you just the output of the latest command. The string returned can be from a few commands back, as if it's stuck in some buffer and can't get out.

So what is the proper way to issue several commands in a single session, taking in the result (as a string) of each command?

I showed you a simple test case for this in my email about too many line feeds (ODOA, or CRLF). This was fixed by altering the source, creating a SshShell.WriteLine2() function that gave \n\r at the end of the line, and modifying SshShell.WriteLine() to only output \r:
        public void WriteLine2(string line)
        {
            var commandText = string.Format("{0}{1}", line, "\r\n");
            
            this.Write(commandText);
        }
        public void WriteLine(string line)
        {
            var commandText = string.Format("{0}{1}", line, "\r");

            this.Write(commandText);
        }
I could have come up with a more intuitive name, but I figure this is a temporary patch/fix. Ideally, this would be chosen by a boolean class level attribute.

I've been trying to concisely log into a Cisco router in enable mode for over a week now. Oddly, SshShell.Flush() seems to have no impact at all on the readstream/buffer.
Nov 10, 2013 at 3:34 PM
I believe I am looking for the same solution you are. I am trying to figure out how to maintain a SSH interactive session so that I can change to a different user. I initially posted at https://sshnet.codeplex.com/discussions/285853.
Nov 10, 2013 at 4:26 PM
I was just able to solve my issue, and I posted the solution on StackOverflow.
Nov 10, 2013 at 9:19 PM
@egagne, I see now that PowerShell is very similar. I, too, took notes from the same emails, and came up with a more .NET-ish solution. So it wouldn't be taken offline, I posted the whole thing (sample code, output, etc.) on my blog here.

To preserve space here, I will say that I created for my tests several functions, a few of which are:
Function SendCommand(cmd As String, s As ShellStream) As String
        Try
            reader = New StreamReader(s)
            writer = New StreamWriter(s)
            writer.AutoFlush = True
            writer.WriteLine(cmd)
            While s.Length = 0
                Thread.Sleep(500)
            End While
        Catch ex As Exception
            Debug.WriteLine("SendCommand(" & cmd & ") caught exception: " & ex.ToString())
        End Try
        Return reader.ReadToEnd()
    End Function
    Function SendCommandW(cmd As String, s As ShellStream) As String
        Try
            reader = New StreamReader(s)
            writer = New StreamWriter(s)
            writer.AutoFlush = True
            writer.Write(cmd)
            While s.Length = 0
                Thread.Sleep(500)
            End While
        Catch ex As Exception
            Debug.WriteLine("SendCommandW(" & cmd & ") caught exception: " & ex.ToString())
        End Try
        Return reader.ReadToEnd()
    End Function
On the blog I take the time to explain why there is more than one SendCommand(). You can probably tell from the above why-especially if you have had to work with Cisco IOS for any length of time.

So all you so is create a ShellStream, and pass it to one of the functions. That function will return only the text from the command. This was the hard part. Once I got it to work, it seemed nothing I tried would clear out the buffers-making all previous input/output part of the current output!

I write in lots of languages, but since everyone here discusses in C# (and the source is in C#), I thought I'd help out the VB.NET folks.

This project, and the DLL/library it creates, are really great. Since I don't know what kind of development help is needed, right now all I can do is pass on some working code for others to get over the difficulties that plagued me for about 20 hours!

Thanks again, folks, and let me know if there is any way I can contribute.

pat
:)
Marked as answer by BogusException on 11/10/2013 at 6:01 PM
Jun 10, 2015 at 7:12 PM
Can you link the solution you found to your problem!? I am having the same issue, i am losing session from all previous commands sent to the server.
Jun 11, 2015 at 5:11 PM
If I can interfere in your topic, I wrote vb.net code with renci ssh.net to manage many Cisco switches & routers.
I added some code in send/receive command for :
  • take out command echo from response buffer
  • take out Ios prompt (<host>#)
  • wait until <prompt> received or when <Timeout> seconds elapsed
  • increase terminal line length in order to do not get special cursor position cars : SSH_Socket.CreateShellStream("dumb", 512, 96, 800, 600, 2000000)
  • remove <Backspace> from response buffer
just know need events in sshclient to detect server disconnection
Alain