Sshnet Command Execution

Execute command with SSH.NET without blocking and keep it running after closing the connection

This is not really SSH.NET question, but rather a generic SSH/shell question.

See How to make a program continue to run after log out from ssh?

So this should do:

client.RunCommand("nohup /home/my-script.sh > foo.out 2> foo.err < /dev/null &");

SshNet Command Execution

The answer to this is the same as the one for your question using the Tamir SSH library - you are using a class intended for executing single commands, which logs in and executes the command each time. You will not be able to use this like a shell.

If you want to implement interactive commands, you'll need something which keeps the connection open, and you'll need to deal with working out when a command has finished (which is normally done by looking for the prompt pattern). The Shell class provides methods for dealing with this - you can find examples of its use on their website.

Providing input/subcommands to a command (cli) executed with SSH.NET SshClient.RunCommand

AFAIK, cli is a kind of a shell/interactive program. So I assume you have tried to do something like:

client.RunCommand("cli");
client.RunCommand("some cli subcommand");

That's wrong. cli will keep waiting for subcommands and never exit, until you explicitly close it with a respective command (like exit). And after it exits, the server will try to execute the cli subcommand as a separate top-level command, failing too.


You have to feed the "cli subcommand" to the input of the cli command. But SSH.NET unfortunately does not support providing an input with the SshClient.RunCommand/SshClient.CreateCommand interface. See Allow writing to SshCommand.


There are two solutions:

  • Use the appropriate syntax of the server's shell to generate the input on the server, like:

    client.RunCommand("echo \"cli subcommand\" | cli");
  • Or use a shell session (what is otherwise a not recommended approach for automating a command execution).

    Use SshClient.CreateShellStream or SshClient.CreateShell and send the commands to its input:

    "cli\n" + "cli subcommand\n"

    For a sample code see Providing subcommands to a command (sudo/su) executed with SSH.NET SshClient.CreateShellStream or C# send Ctrl+Y over SSH.NET.

How to run commands on SSH server in C#?

You could try https://github.com/sshnet/SSH.NET.
With this you wouldn't need putty or a window at all.
You can get the responses too.
It would look sth. like this.

SshClient sshclient = new SshClient("172.0.0.1", userName, password);    
sshclient.Connect();
SshCommand sc= sshclient .CreateCommand("Your Commands here");
sc.Execute();
string answer = sc.Result;

Edit: Another approach would be to use a shellstream.

Create a ShellStream once like:

ShellStream stream = sshclient.CreateShellStream("customCommand", 80, 24, 800, 600, 1024);

Then you can use a command like this:

  public StringBuilder sendCommand(string customCMD)
{
StringBuilder answer;

var reader = new StreamReader(stream);
var writer = new StreamWriter(stream);
writer.AutoFlush = true;
WriteStream(customCMD, writer, stream);
answer = ReadStream(reader);
return answer;
}

private void WriteStream(string cmd, StreamWriter writer, ShellStream stream)
{
writer.WriteLine(cmd);
while (stream.Length == 0)
{
Thread.Sleep(500);
}
}

private StringBuilder ReadStream(StreamReader reader)
{
StringBuilder result = new StringBuilder();

string line;
while ((line = reader.ReadLine()) != null)
{
result.AppendLine(line);
}
return result;
}

Commands fail with “command not found”, when executed using SSH.NET CreateCommand in C#

The SSH.NET SshClient.CreateCommand (or SshClient.RunCommand) does not run shell in "login" mode and does not allocate a pseudo terminal for the session. As a consequence a different set of startup scripts is (might be) sourced (particularly for non-interactive sessions, .bash_profile is not sourced), than in your regular interactive SSH session. And/or different branches in the scripts are taken, based on an absence/presence of TERM environment variable.

Possible solutions (in preference order):

  1. Fix the command not to rely on a specific environment. Use a full path to ideviceinstaller in the command. E.g.:

     /path/to/ideviceinstaller ...

    If you do not know the full path, on common *nix systems, you can use which ideviceinstaller command in your interactive SSH session.

  2. Fix your startup scripts to set the PATH the same for both interactive and non-interactive sessions.

  3. Try running the script explicitly via login shell (use --login switch with common *nix shells):

     bash --login -c "ideviceinstaller ..."
  4. If the command itself relies on a specific environment setup and you cannot fix the startup scripts, you can change the environment in the command itself. Syntax for that depends on the remote system and/or the shell. In common *nix systems, this works:

     PATH="$PATH;/path/to/ideviceinstaller" && ideviceinstaller ...
  5. Another (not recommended) is to use "shell" channel to execute the command via SshClient.CreateShellStream or SshClient.CreateShell as these allocate pseudo terminal

     ShellStream shellStream = client.CreateShellStream(string.Empty, 0, 0, 0, 0, 0);
    shellStream.Write("ideviceinstaller\n");

    while (true)
    {
    string s = shellStream.Read();
    Console.Write(s);
    }

    Using the shell and pseudo terminal to automate a command execution can bring you nasty side effects.

NOT getting the full output from ssh.net SshCommand

Okay. As @MartinPrikryl pointed out in the comments above.

The SshCommand() method does not access the shell. (it uses the "exec" channel in the SSH.NET API).

If you want to access the "shell" using SSH.NET, then you will need to use the "ShellStream".

here is a link to 27 different examples of how others have used ShellStream in the real world.
https://csharp.hotexamples.com/examples/Renci.SshNet/ShellStream/-/php-shellstream-class-examples.html

SSH.NET is not executing command on device

Your server obviously does not support the SSH "exec" channel that is used behind the SSH.NET SshClient.RunCommand method and PLink's plink.exe command syntax.

Or actually it does support it, but incorrectly. It seems to start an interactive session (a shell), instead of executing the command.

To confirm this assumption, try this with PLink:

echo AT| plink username@ip -pw password > log.txt

If that works, you may need to use the SshClient.CreateShell (SSH "shell" channel") and write the command to its input stream, instead of using the SshClient.RunCommand. While this is generally a wrong approach, you need to take this approach due to your broken server.


A similar question for Python/Paramiko:

Executing command using Paramiko exec_command on device is not working
.



Related Topics



Leave a reply



Submit