How to run several commands with SSH.Net? [duplicate] - c#

I need to execute this action using a C# code:
open putty.exe in the background (this is like a cmd window)
login to a remote host using its IP address
enter a user name and password
execute several commands one after the other.
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);

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;
}

While the answer by #LzyPanda works, using an SSH "shell" channel (SshClient.CreateShellStream), let alone 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.

Related

How to run CMD and plug in a command from a bot azure program if intent is recognized?

Below is a sample intent from the Azure SDK bot that runs in the bot framework emulator. The bot recognizes my intent by returning a string type response. This was just a preparation for the bot, when it recognizes my intention, it is supposed to run the CMD program and execute the command in the system, and after executing the command in the CMD and completing this, it will return a response that the command was executed.... However, as you can see below, unfortunately this does not work. Instead, the bot immediately returns all responses without waiting and running the command in CMD.
case WebAppBotTester.Intent.TestPageOne:
var getSearchActionText = "Redirecting to the Action and run CMD, wait...";
var getSearchActionMessage = MessageFactory.Text(getSearchActionText, getSearchActionText, InputHints.IgnoringInput);
await stepContext.Context.SendActivityAsync(getSearchActionMessage, cancellationToken);
string command = #"cd ..\\..& cd tests & npx [MAKE ACTION..]";
ProcessStartInfo cmdsi = new ProcessStartInfo("cmd.exe");
cmdsi.Arguments = command;
Process cmd = Process.Start(cmdsi);
cmd.WaitForExit();
var getresultActionText = "The result is ready!";
var getresultActionMessage = MessageFactory.Text(getresultActionText , getresultActionText, InputHints.IgnoringInput);
await stepContext.Context.SendActivityAsync(getresultActionMessage, cancellationToken);
break;
What am I doing wrong ?
This solved my problem:
I have written a simple NodeJsServer class in C# that can help you
with these things. It is available on GitHub here. It has a lot of
options, you can execute 'npm install' commands in specific
directories, or start NodeJs, check the current status (is it running,
is it compiling, is it starting, is it installing) and finally stop
the NodeJs. Check the quick example usage.
This is the raw code (copied mostly from the NodeJsServer class) of
what you are trying to do:
// create the command-line process
var cmdProcess = new Process
{
StartInfo =
{
FileName = "cmd.exe",
UseShellExecute = false,
CreateNoWindow = true, // this is probably optional
ErrorDialog = false, // this is probably optional
RedirectStandardOutput = true,
RedirectStandardInput = true
}
};
// register for the output (for reading the output)
cmdProcess.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
{
string output = e.Data;
// inspect the output text here ...
};
// start the cmd process
cmdProcess.Start();
cmdProcess.BeginOutputReadLine();
// execute your command
cmdProcess.StandardInput.WriteLine("quicktype --version");

SSH.net crushed when called to run remote opencv program

I have a opencv program as a server to send image stream from camera. Now I have to make a c# program to open the opencv program remotely.
everything is good by using ssh via cmd.
like:
ssh myname#ip
export DISPLAY=":0"
~/home/MyName/MyOpencvProgram
and I can see a imshow windows pop-up in my server computer.
Now I want to make this in c# WPF program so I use SSH.NET package:
public void TrySomeSSh()
{
ConnectionInfo conInfo = new ConnectionInfo(ip, _port, _username, new AuthenticationMethod[]{
new PasswordAuthenticationMethod(_username,_password)});
SshClient sshClient = new SshClient(conInfo);
sshClient.Connect();
if (sshClient.IsConnected)
{
SshCommand output1;
string line1 = "export DISPLAY=\":0\"";
output1 = sshClient.RunCommand(line1);
Console.WriteLine(output1.Execute());
Console.WriteLine(line1);
string line = "/home/MyName/MyOpencvProgram";
Console.WriteLine(line);
var output2 = sshClient.RunCommand(line);
Console.WriteLine(output2.Execute());
}
else
{
Console.WriteLine("not connected");
}
sshClient.Disconnect();
sshClient.Dispose();
}
from the output.Execute() I can see the program is running. However it would always stop when meet some GUI function like namedwindow() , imshow() , or waitKey() .All of these work fine when use ssh via cmd, and I think the export DISPLAY=":0" command is enough to solve this. But It still stopped.
What should I do now?
thanks Prikryl's comment, as the link says each RunCommand() function runs in their own shell ,RunCommand() would not remember the variable we give. So we have to put the command together
like:
public void TrySomeSSh()
{
ConnectionInfo conInfo = new ConnectionInfo(ip, _port, _username, new AuthenticationMethod[]{
new PasswordAuthenticationMethod(_username,_password)});
SshClient sshClient = new SshClient(conInfo);
sshClient.Connect();
if (sshClient.IsConnected)
{
SshCommand output1;
output1 = sshClient.RunCommand("export DISPLAY=\"127.0.0.1:10.0\" ; /home/MyName/MyOpencvProgram ");
Console.WriteLine(output1.CommandText);
Console.WriteLine(output1.Execute());
}
else
{
Console.WriteLine("not connected");
}
sshClient.Disconnect();
sshClient.Dispose();
}

Sending Ctrl+break sequence through Plink

I am trying to automate the remote server shell commands through Plink. And one of the things which I did is grep command.
Now suppose if results lots of data then I just want to break the command.
Generally from PuTTY you just do Ctrl-C or Ctrl-Break and it will break the command.
What's the alternative for Plink?
Do not run Plink from C# application to implement SSH. Use a native .NET implementation of SSH, like SSH.NET. – It will give you a complete control over the connection and you won't have have to use hacks like sending Ctrl+C.
var client = new SshClient("example.com", "username", "password");
client.Connect();
SshCommand command = client.CreateCommand("grep pattern file");
IAsyncResult result = command.BeginExecute();
using (var outputReader = new StreamReader(command.OutputStream))
using (var extendedReader = new StreamReader(command.ExtendedOutputStream))
{
int read = 0;
while (read < 10240)
{
string s;
s = outputReader.ReadToEnd();
read += s.Length;
Console.Write(s);
s = extendedReader.ReadToEnd();
read += s.Length;
Console.Write(s);
}
}
command.CancelAsync();
Also, you can use -m switch to stop grep after certain number of matches.

Execute multiple dependent SSH commands using SSH.NET in C#

I want to change directory inside SSH using C# with SSH.NET library:
SshClient cSSH = new SshClient("192.168.80.21", 22, "appmi", "Appmi");
cSSH.Connect();
Console.WriteLine("current directory:");
Console.WriteLine(cSSH.CreateCommand("pwd").Execute());
Console.WriteLine("change directory");
Console.WriteLine(cSSH.CreateCommand("cdr abc-log").Execute());
Console.WriteLine("show directory");
Console.WriteLine(cSSH.CreateCommand("pwd").Execute());
cSSH.Disconnect();
cSSH.Dispose();
Console.ReadKey();
But it's not working. I have also checked below:
Console.WriteLine(cSSH.RunCommand("cdr abc-log").Execute());
but still is not working.
I believe you want the commands to affect the subsequent commands.
But SshClient.CreateCommand uses SSH "exec" channel to execute the command. That means that every command is executed in an isolated shell and has no effect on the other commands.
If you need to execute commands in a way that previous commands affect later commands (like changing a working directory or setting an environment variable), you have to execute all commands in the same channel. Use an appropriate construct of the server's shell for that. On most systems you can use semicolons:
Console.WriteLine(cSSH.CreateCommand("pwd ; cdr abc-log ; pwd").Execute());
On *nix servers, you can also use && to make the following commands be executed only when the previous commands succeeded:
Console.WriteLine(cSSH.CreateCommand("pwd && cdr abc-log && pwd").Execute());
Some less common systems (for example AIX) may not even have a way to execute multiple commands in one "command-line". In these cases, you may need to use a shell channel, what is otherwise not recommended.
Also when the other commands are actually sub commands of the first command, you may need different solution.
See Providing subcommands to a command (sudo/su) executed with SSH.NET SshClient.CreateShellStream.
this is what I have done and its working for me:
SshClient sshClient = new SshClient("some IP", 22, "loign", "pwd");
sshClient.Connect();
ShellStream shellStream = sshClient.CreateShellStream("xterm", 80, 40, 80, 40, 1024);
string cmd = "ls";
shellStream.WriteLine(cmd + "; echo !");
while (shellStream.Length == 0)
Thread.Sleep(500);
StringBuilder result = new StringBuilder();
string line;
string dbt = #"PuttyTest.txt";
StreamWriter sw = new StreamWriter(dbt, append: true);
while ((line = shellStream.ReadLine()) != "!")
{
result.AppendLine(line);
sw.WriteLine(line);
}
sw.Close();
sshClient.Disconnect();
sshClient.Dispose();
Console.ReadKey();

How to issue SSH command

I am using C# with SSH.NET.
I want to issue a PWD command but could not find any documentation or help. I do not know how to use 'SshClient' class.
Update:
I also tried experimenting with SshClient class using the below code but it does nothing, neither any error nor any exception.
ConnectionInfo ConnNfo = new ConnectionInfo("FTPHost", 22, "FTPUser",
new AuthenticationMethod[]{
// Pasword based Authentication
new PasswordAuthenticationMethod("FTPUser","FTPPass")
}
);
using (var ssh = new SshClient(ConnNfo))
{
ssh.Connect();
if (ssh.IsConnected)
{
string comm = "pwd";
using (var cmd = ssh.CreateCommand(comm))
{
var returned = cmd.Execute();
var output = cmd.Result;
var err = cmd.Error;
var stat = cmd.ExitStatus;
}
}
ssh.Disconnect();
}
Nothing happens. Neither an error nor an exception. On Visual Studio console, i get the below output.
*SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelRequestMessage': 'SSH_MSG_CHANNEL_REQUEST : #152199'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server:
'ChannelFailureMessage': 'SSH_MSG_CHANNEL_FAILURE : #0'.*
At ssh.RunCommand method call the program goes in some sleep state (or waits for around 1 minute). sshCommand.Result and sshCommand.Error variables are empty.
Here's a quick example - one way to do it.
string host = "myhost";
string user = "root";
string pwd = "#secret#!"; // Don't use hardcoded plain-text passwords if possible - for demonstration only.
using (PasswordAuthenticationMethod auth = new PasswordAuthenticationMethod(user, pwd))
{
ConnectionInfo connection = new ConnectionInfo(host, user, auth);
using (var ssh = new SshClient(connection))
{
ssh.Connect();
SshCommand sshCommand = ssh.RunCommand("pwd");
Console.WriteLine("Command execution result: {0}", sshCommand.Result);
}
}
Note that if you specify an invalid command (e.g. "pwdxxxx"), you won't get an exception, but an error that will be stored in the SshCommand.Error string.
Note also that this uses SSH PasswordAuthentication, which may not be enabled in your SSH config.
Try looking into the documentation of SSH.NET:
SSH.NET at CodePlex
Code sample for executing a command (recommended)
Help file.CHM

Categories

Resources