How to run commands on SSH server in C#?

32,780

Solution 1

You could try https://sshnet.codeplex.com/. 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;
    }

Solution 2

While the answer by @LzyPanda works, using an SSH "shell" channel (SshClient.CreateShellStream), let only an interactive terminal, is not a good idea for automating commands execution. You get lot of side-effects from that, like command prompts, ANSI sequences, interactive behavior of some commands, etc.

For automation, use an SSH "exec" channel (SshClient.CreateCommand):

using (var command = ssh.CreateCommand("command"))
{
    Console.Write(command.Execute());
}

If you need to execute multiple commands, repeat the above code. You can create any number of "exec" channels for one SSH connection.

Though if the commands depend on each other (first command modified the environment, e.g. variables, that are used by the latter commands), you have execute them within one channel. Use a shell syntax for that, like && or ;:

using (var command = ssh.CreateCommand("command1 && command2"))
{
    Console.Write(command.Execute());
}

If you need to continuously read the commands output use:

using (var command = ssh.CreateCommand("command"))
{
    var asyncExecute = command.BeginExecute();
    command.OutputStream.CopyTo(Console.OpenStandardOutput());
    command.EndExecute(asyncExecute);
}

You can also use ExtendedOutputStream, which contains stderr. See SSH.NET real-time command output monitoring.


Unfortunately implementation of "exec" channel in SSH.NET does not allow providing an input to the command. For that use case, you will need to resort to the "shell" channel, until this limitation is solved.

Share:
32,780
Liran Friedman
Author by

Liran Friedman

BY DAY: I work as a C# server side developer. BY NIGHT: Mostly R&D for fun, investigating new technologies, learning new things in development. Currently focusing on Android development. FOR FUN: Hanging out with the family.

Updated on July 09, 2022

Comments

  • Liran Friedman
    Liran Friedman almost 2 years

    I need to execute this action using a C# code:

    1. open putty.exe in the background (this is like a cmd window)
    2. login to a remote host using its IP address
    3. enter a user name and password
    4. execute several commands one after the other.
    5. run another command that gets a response telling me that the commands I ran before that where executed successfully

    So I'm trying to do it like this:

    ProcessStartInfo proc = new ProcessStartInfo() 
    {
         FileName = @"C:\putty.exe",
         UseShellExecute = true, //I think I need to use shell execute ?
         RedirectStandardInput = false,
         RedirectStandardOutput = false,
         Arguments = string.Format("-ssh {0}@{1} 22 -pw {2}", userName, hostIP, password)
         ... //How do I send commands to be executed here ?
    };
    Process.Start(proc);