I've written my own interface into Linux with my own translation of commands and Ansible extensions. I'm using Visual Studio 2019, connecting to CentOS, running the latest Ansible, while connecting using SSH.NET.
Because this is 1000's of lines of code, this is a very high level sudo code, I'm doing this:
const string Command_Prompt = #"[\?$#]|\[.*#(.*?)\][$%#]";
var promptRegex = new Regex(Command_Prompt);
while(_lastCommand != "exit") {
_lastCommand = Console.ReadLine();
_shellStream.WriteLine(_lastCommand);
var output = _shellStream.Expect(promptRegex);
Log.Verbose(output);
}
This picks up
[root#localhost ~]#
[root#localhost ~]$
#
$
What is your first name?
My Ansible ymls have promtps and this works perfectly if the prompt has a question mark. If I'm expecting something specific it works fine as I can pass into expect anything I like. However, there are times, I run a linux command and the command has a prompt that is unexpected, this is waiting for the expected information to come back. Is there no way to do what MRemote, Putty, or VSCode terminal does with unknown prompts? I can't really allow others to use my product if I don't know what their prompts are going to look like. What does MRemote, Putty and VSCode terminal do specifically that SSH.NET clearly doesn't do or am I'm not using SSH.NET correctly?
I ended up, just go with the basics.
.*\?:|[$#]|\[.*#(.*?)\][$%#]
Picks up the following
[root#localhost ~]#
[root#localhost ~]$
#
$
What is your first name?:
Related
I created a program using Renci SSH.NET library. Its sending all the commands and reading the result normally. However, when I send the command below:
client.RunCommand("cli");
The program hangs on this line indefinitely.
Any explanation of what is happening?
The cli is a command is used on Juniper switches/routers.
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.
I have some large project that connect to many devices over SSH.NET
Now I have to add support for new modem witch is digi 6030dx.
I added it and I am able to connect with no issues
But when I send some/any command like show config the output is:
[16C[0K
[16C[0Ks
[17C[0Kh
[18C[0Ko
[19C[0Kw
[20C[0K
[20C[0Kc
[21C[0Ko
[22C[0Kn
[23C[0Kf
[24C[0Ki
[25C[0Kg
Commands
-------------------------------------------------------------------------------
config View and modify the configuration
exit Exit the CLI
analyzer Analyzer commands.
cli-legacy Enter the legacy Admin CLI.
cp Copy a file or directory.
help Show CLI editing and navigation commands.
ls List a directory.
mkdir Create a directory.
modem Modem commands.
more View a file.
mv Move a file or directory.
ping Ping a host.
reboot Reboot the system.
rm Remove a file or directory.
scp Copy a file or directory over SSH.
show Show instance statistics.
system System commands.
traceroute Print the route packets trace to network host.
update Update firmware.
dra.wk.0001> ashowconfigdra.wk.0001> ashowconfig
[16C[0K
Does anyone known what are this strange signs / why my command is splited by this and newlines?
It is first device that have this issue and the app support over 200 other with no issues.
I guess some coding issue or something ? putty does not show this signs so probably 'understand' them somehow?
Those are ANSI escape codes.
In general, with SSH, you get these only if your client (library) declares support for terminal emulation.
SSH.NET library does that always, when you use the "shell" channel (SshClient.CreateShell or SshClient.CreateShellStream).
In general (were you connecting to well behaving SSH server), to avoid getting the codes:
Use "exec" channel (use SshClient.RunCommand). SSH.NET does not use terminal emulation on "exec" channel. Though SSH servers on "devices" (contrary to full servers) usually do not implement the "exec" channel. See also What is the difference between exec_command and send with invoke_shell() on Paramiko?
Modify SSH.NET code not to request terminal emulation for the "shell" channel. – Remove SendPseudoTerminalRequest request from Shell.Start implementation.
Though as you are connecting to some "device" and telneting further to another device and the codes probably come from the far device, the question is whether this will in fact have any effect on that device at all. Possibly you won't be able to avoid getting the codes. Lack of terminal emulation on the first SSH connection possibly won't have any effect on the second telnet connection.
In the end, you may have to deal with the codes.
See also How to strip ANSI escape codes from AIX topas command result in C#.
i did for now
this.answer = Regex.Replace(this.answer, #"\r\[\d{0,3}C\[0K", "", RegexOptions.IgnoreCase);
will see if have any negative impact but looks perfect for now :D
I created a program using Renci SSH.NET library. Its sending all the commands and reading the result normally. However, when I send the command below:
client.RunCommand("cli");
The program hangs on this line indefinitely.
Any explanation of what is happening?
The cli is a command is used on Juniper switches/routers.
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.
I'm definitely new to C# but learning it to pickup where another left things at work so be gentle if I ask silly questions (I think this is an easy one). I'm using SSH.NET and the current code isn't wrong but the way the previous guy wrote it can leave open ssh connections on the other side.
Current working code opens the SSH session as normal but uses something like this to run commands on the remote system:
Stream.Writeline("part of the command")
Stream.Readline();
Stream.Writeline("second part of command")
Stream.Readline();
Stream.Writeline("last part of command")
Stream.Readline();
This works and gathers the data exactly as it should but I've seen repeated times where the SSH connection stays open afterwards on the remote system. What I would like to do is send this all within a single command via create.command like:
command1 = client.CreateCommand("full command to run")
result = command1.Execute()
My problem is that the command I'd like to run on the remote system requires returns to run, it's a database command:
mysql -u user <<EOF
select COUNT(*) from table1
go
EOF
What I'd like to do:
command1 = client.CreateCommand("mysql -u user <<EOF\nselect COUNT(*) from table1\ngo\nEOF\n")
How/can one insert returns into the Create.Command? I'm assuming so, see no reason why not but I'm having a hard time finding the correct syntax to send a database command that requires returns after each line like above via the Create.Command. I've tried using \n for newlines but 99% sure I'm using it incorrectly.
And just to be clear I used mysql as the DB example, it's actually a sybase database but uses that syntax to connect.
Why do you need the breaks in the first place? They're just to nicely format the query for humans. MySQL isn't human. It couldn't care less. why not just do it this?
mysql -u user -e 'select count(*) from table1'
you don't need a go command, period.
If you DO want to send multiple commands, then you still don't need any line breaks, just a ;:
mysql -u user -e 'command1; command2; command3; ....'
USE \r\n like in here:
command1 = client.CreateCommand("mysql -u user <<EOF\r\nselect COUNT(*) from table1\r\ngo\r\nEOF\n")
I have an .apk package that i want to push it into android emulator and run in emulator and then receive events and debug message to show to user with C# console program.
How should i connect to android emulator for receiving debug message from C# code console?
please help me. Thanks.
This depends on how much detail you want. Do you simply want to view the logcat or get full debug info(like breakpoints and device statistics)?
In the case of the former:
You can use the adb(Android Debug Bridge):
ProcessStartInfo adbStart = new ProcessStartInfo(#"your_path\android-sdk\platform-tools\adb.exe", "-e logcat *:D");
adbStart.UseShellExecute = false;
Process adb = new Process() { StartInfo = adbStart };
adb.Start();
Replace the first parameter in the constructor of adbStart with the path to your adb.exe, found in the platform_tools folder of your Android SDK. The second parameter is console flags. The above code forces the adb to only connect to an emulator using the -e flag and filters to debug messages only using the *:D flag. You should replace the * with a relevant filter for your app(like a package name). Just type adb help in a console for info on the different flags.
Since your program runs in the console, the standard output of the adb SHOULD be directed to your console. If it isn't, use the StreamReader at adb.StandardOutput to read the output of the adb. You can use adb.WaitForExit() to block the thread until adb dies.
In the case of the latter:
The official way to do this is via the Dalvik Debug Monitor(android_sdk\tools\ddms.bat). Since there is no official support for C# in android, the debug monitor is written in Java and so are the libs. I can't find any substitutes, sorry. Java is very similar to C# though, maybe you can jump languages for this particular project?