This project is read-only.

Running commands not returning results

Dec 3, 2014 at 8:52 PM
I've created a SignalR SSH web console and I'm trying to run simple commands like "?" but I do not get a response, just an empty string. Here is a code sample:
            SshClient client;
            if (!SshClients.TryGetValue(connectionId, out client))
            {
                Clients.All.receive("ERROR: connection object not found");
                return;
            }

            if (!client.IsConnected)
                client.Connect();

            var sshCommand = client.CreateCommand(command);
            var asynch = sshCommand.BeginExecute();
            var reader = new StreamReader(sshCommand.OutputStream);

            while (!asynch.IsCompleted)
            {
                var result = reader.ReadToEnd();
                if (string.IsNullOrEmpty(result))
                    continue;
                Clients.All.receive(result);
            }
            sshCommand.EndExecute(asynch);
Dec 3, 2014 at 9:22 PM
Edited Dec 3, 2014 at 9:22 PM
Also read/show the content of ExtendedOutputStream , which contains the data from StdErr.
OutputStream just holds data from StdOut.
Maybe your output is printed to StdErr?
Dec 3, 2014 at 10:20 PM
Also when I debug the app it never leaves the while loop, so it never gets to the sshCommand.EndExecute(asynch) statement. Should I use a different function?
Dec 4, 2014 at 7:17 AM
Looks good in a simple test program:
            var sshCommand = client.CreateCommand("pwd");
            var asynch = sshCommand.BeginExecute();
            var reader = new StreamReader(sshCommand.OutputStream);
            var errreader = new StreamReader(sshCommand.ExtendedOutputStream);

            while (!asynch.IsCompleted)
            {
                var result = reader.ReadToEnd();
                var error = errreader.ReadToEnd();
                if (string.IsNullOrEmpty(result) && string.IsNullOrEmpty(error))
                    continue;
                Console.WriteLine("StdErr: " + error);
                Console.WriteLine("StdOut: " + result);
            }
=>
StdErr:
StdOut: /root
Dec 4, 2014 at 4:15 PM
Edited Dec 4, 2014 at 4:20 PM
Some commands are still freezing on the errreader.ReadToEnd() . Also command response in inconsistent. I can run the exact same command twice, first time it works, second time no response.
       cat /etc/*-release
Another issue is If I change the current directory it doesn't remember it between commands. Here is how I'm creating a connection:
        var PasswordConnection = new PasswordAuthenticationMethod(username, password);
        var KeyboardInteractive = new KeyboardInteractiveAuthenticationMethod(username);
        var connectionInfo = new ConnectionInfo(servername, username, PasswordConnection, KeyboardInteractive);

        var client = new SshClient(connectionInfo);
        client.Connect();
Dec 4, 2014 at 4:24 PM
Edited Dec 4, 2014 at 4:40 PM
tirrellcotton wrote:
Some commands are still freezing on the errreader.ReadToEnd() . Also command response in inconsistent. I can run the exact same command twice, first time it works, second time no response.
       cat /etc/*-release

Can you ensure on the server the command exits?
e.g. ps auxwww | grep cat

Can you also ensure the Connection is still up if the ReadToEnd() is hanging?
Another issue is If I change the current directory it doesn't remember it between commands. Here is how I'm creating a connection:
RunCommand() uses the ssh command feature. Means each command is started in it's own new "shell".

client.RunCommand("pwd")
=> $HOME

client.RunCommand("cd /tmp")
client.RunCommand("pwd")
=> $HOME

client.RunCommand("cd /tmp && pwd")
=> /tmp

If you want the same environment for all command, you have to use a ShellStream.
Dec 4, 2014 at 4:41 PM
  Can you ensure on the server the command exits? 
  e.g. ps auxwww | grep cat
The command exists because the first time I get results, but not after that.
 RunCommand() uses the ssh command feature. Means each command is started in it's own new "shell". 
I'm not using client.RunCommand unless the sshCommand.BeginExecute() is using it.
 If you want the same environment for all command, you have to use a ShellStream.
I'll look at the test scripts to see how to do this
Dec 4, 2014 at 4:48 PM
exits not exists. I'm pretty sure cat exists on every system out there :)

Please check the connection state when the ReadToEnd() hangs. I think I can trigger your problem with this:
            while (true)
            {

                var sshCommand = client.CreateCommand("cat /etc/*-release");
                var asynch = sshCommand.BeginExecute();

                while (!asynch.IsCompleted)
                {
                    Console.WriteLine("waiting");
                    Thread.Sleep(10);
                }
                client.Disconnect();

                sshCommand.EndExecute(asynch);
                Console.WriteLine("Date: " + DateTime.Now);
                Console.WriteLine("StdErr: " + sshCommand.Error);
                Console.WriteLine("StdOut: " + sshCommand.Result);
                Console.WriteLine("ExitCode: " + sshCommand.ExitStatus);

                Thread.Sleep(1000);
            }
=> I get one Output, the next one hangs.

Yes, I should have written SshCommand, not RunCommand().


Here is simple example of ShellStream with async read:
        private static byte[] _data = new byte[2048];
        private static ShellStream stream;
        private static SshClient client;

        private static void Main()
        {
            client = new SshClient("test", "test", "test");
            client.Connect();

            stream = client.CreateShellStream(@"xterm", 80, 24, 800, 600, 1024);
            stream.DataReceived += StartAsyncRead;
            stream.Write("env | grep TERM\n");
            stream.Write("echo $TERM\n");

            Console.ReadLine();
        }

        private static void StartAsyncRead(object sender, EventArgs e)
        {
            try
            {
                stream.BeginRead(_data, 0, _data.Length, OnReadCompletion, new MyAsyncInfo(_data, stream));
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }

        private static void OnReadCompletion(IAsyncResult ar)
        {
            try
            {
                var mai = (MyAsyncInfo) ar.AsyncState;
                int datalen = mai.Stream.EndRead(ar);
                string line = client.ConnectionInfo.Encoding.GetString(mai.ByteArray, 0, datalen);
                Console.Write(line);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }
    }

    public class MyAsyncInfo
    {
        public MyAsyncInfo(Byte[] array, ShellStream stream)
        {
            ByteArray = array;
            Stream = stream;
        }

        public Byte[] ByteArray { get; set; }
        public ShellStream Stream { get; set; }
    }
Dec 5, 2014 at 9:29 PM
Have you tried to turn on the blocking mode in the SshCommand.OutputStream?
In this thread there is a example how it works nice:
https://sshnet.codeplex.com/discussions/572434

I used this method and it did always work.
Mar 11, 2015 at 10:24 PM
Edited Mar 11, 2015 at 10:28 PM
I am trying to send commands to an HP blade through the iLO. This works like a charm from the console. But I need to return the results (the string line in OnReadCompletion) to the calling method. Any ideas on how to do this? Thanks in advance.