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.
Related
I'm trying to execute a command from inside a .NET process. The command works just fine in Powershell or a regular command prompt executed by the same user as used for the .NET process.
I am trying to update the RRAS SSTP cert on Windows server 2016 with the following command:
netsh ras set sstp-ssl-cert name=bla.domain.foo
The error I'm getting is the following:
The supplied kernel information version is invalid.
This is the code I'm using to execute from inside a simple .NET console application. Outputting logic omitted for brevity.
using (var powerShellInstance = PowerShell.Create())
{
powerShellInstance.AddScript(command);
powerShellInstance.Invoke();
}
I'm using the .NET framework 4.6.1, I have tried adding a manifest to up the required execution rights but neither that or running as admin manually changes anything.
The application is executed by a scheduled task and if I manually add the required script as a step directly executing with cmd.exe it works like a charm. This is not very clean however, and requires me knowing the cert name when creating the task. There are a million ways I can overcome this issue but for the life of me I don't understand why it doesn't just work from .NET while all other commands I require are working fine.
So, this is not really a PoSH specific thing natively. That error message is more general than specific to .Net use case.
This error message is not unique to what you at doing, especially most recently on Win10. This error has been reported, since the 1703 release, even just when doing things on the file system, like WDS captures, folder creation etc.
Several reasons have been postulated, permissions and the like, but all had to just come up with a workaround (permission fixes, etc.) as you have indicated the you have a million ways to address your use case.
But to get to potential root cause, you need to look deeper at the other Windows event log information, Application, Security, System and PowerShell logs from when you are doing your .Net effort.
I have a web service that uses SSH.NET to call a shell script on a Unix box.
If I run the script normally, it works fine, does its work correctly on the Informix DB.
Just some background:
I call a script that executes a .4gl (cant show this as its business knowledge).
The g4l is giving the following error back in a log, when I execute it with SSH.NET:
fglgo: error while loading shared libraries: libiffgisql.so: cannot open shared object file: No such file or directory
file_load ended: 2017-09-21 15:37:01
C# code to execute SSH.NET script
sshclients = new SshClient(p, 22, username, password);
sshclients.Connect();
sshclients.KeepAliveInterval = new TimeSpan(0, 0, 1);
sshclients.RunCommand("sh " + Script_dir);
I added the KeepAliveInterval, to see, if it helps.
My question is the error I am getting from Unix/4gl.
Why is this happening and who can I get the script to execute correctly?
The SshClient.RunCommand uses SSH "exec" channel internally. It, by default, (rightfully) does not allocate a pseudo terminal (PTY) for the session. As a consequence a different set of startup scripts is (might be) sourced. And/or different branches in the scripts are taken, based on absence/presence of the TERM environment variable. So the environment might differ from the interactive session, you use with your SSH client.
So, in your case, the PATH is probably set differently; and consequently the shared object cannot be found.
To verify that this is the root cause, disable the pseudo terminal allocation in your SSH client. For example in PuTTY, it's Connection > SSH > TTY > Don't allocate a pseudo terminal. Then, go to Connection > SSH > Remote command and enter your g4l command. Check Session > Close window on exit > Never and open the session. You should get the same "No such file or directory" error.
Ways to fix this, in preference order:
Fix the scripts not to rely on a specific environment.
Fix your startup scripts to set the PATH the same for both interactive and non-interactive sessions.
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:
sshclients.RunCommand("PATH=\"$PATH;/path/to/g4l\" && sh ...");
Another (not recommended) approach is to force the pseudo terminal allocation for the "exec" channel.
Though SSH.NET does not support this. You would have to modify its code issue SendPseudoTerminalRequest request in .RunCommand implementation (I didn't test this).
You can also try to use "shell" channel using .CreateShell method. For it, SSH.NET does support pseudo terminal allocation.
Though, using the pseudo terminal to automate a command execution can bring you nasty side effects. See for example Is there a simple way to get rid of junk values that come when you SSH using Python's Paramiko library and fetch output from CLI of a remote machine?
For a similar issues, see
Renci SSH.NET - no result string returned for opmnctl
Certain Unix commands fail with "... not found", when executed through Java using JSch
Commands executed using JSch behaves differently than in SSH terminal (bypasses confirm prompt message of "yes/"no")
JSch: Is there a way to expose user environment variables to "exec" channel?
Have seen similar questions asked by Informix-4gl developers as they transition to FourJs Genero and using its Web Services functionality. The question I'll put to them is "who owns the fglgo/fglrun process that the Genero Application Server has launched, where is it running from, and what is its environment". If needed, I'll illustrate with a simple program that does something like ...
MAIN
RUN "env > /tmp/myname.txt"
RUN "who >> /tmp/myname.txt"
RUN "pwd >> /tmp/myname.txt"
END MAIN
... and say compare with when program is running from command line. It is normally a case like in the earlier answer of configuring so that the environment is set correctly before the 4gl program is executed.
I'm trying to send a simple command over SSH using SSH.NET. Even the simplest test code fails. Here is a snippet.
using (var ssh = new SshClient("ip", port, "username", "password"))
{
ssh.Connect();
while (true)
{
var result = ssh.RunCommand("AT").Execute();
Console.Out.WriteLine(result);
}
}
The AT command should echo back OK but doesn't. Instead I receive a custom timeout message issued by the SSH target. I see the device name in the timeout message which corresponds to the prompt it uses and from that i can conclude that the login works (also tested with various SSH programs) but the command itself is not executed. I tried adding \n and \r\n to the commands but to no results. What am I doing wrong?
Edit 1:
output from result is \r\nCommand Line Interface\r\nDeviceName> Custom idle timeout I think the line endings are converted to Windows ones by Visual Studio.
Edit 2:
Using Plink plink.exe username#ip -pw password "AT" > log.txt results in the same output as Visual Studio. Plink waits till timeout and terminates and log.txtcontains \r\nCommand Line Interface\r\nDeviceName> Custom idle timeout.
Using PuTTY I see that
Using username "username".
username#host's password:
Entering character mode
Escape character is '^]'.
Command Line Interface
DeviceName>
is written before you can start entering commands. Might it be that the command is entered before the host is ready to receive it and as a result the command hangs until some reaction comes?
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.
The original Unix implementation simply did something like this:
ssh [batchname] < [inputfilename] > [outputfilename]
I need to be able to do the same thing from a windows machine running an application written in C#. I've tried using SharpSsh, which includes input and output streams, but they don't seem to work.
How can I pipe the input and output files/streams using SharpSsh (or any other .Net library)?
Figured it out. Either the application running or SSH itself expects a ctrl-d to signal the end of the input. At that point, the output stream can be read without hanging.
I've been trying very hard to automatically ssh into a Linux server. What's crazy, is that I can create a .bat script, that will do it, but I have to be there physically, to type in the password.
I've tried automating this using System.Diagnostics.Process object in c# to no end. There is no way, I've found, to make this object allow you to see the password prompt. It out puts every line up until that point, and then doesn't output any more lines.
cmd.exe, does really well at allowing you to jump from process to process in a script; It consolidates everything into one screen, and just prompts you for things such as passwords, and then you type them in.
Is there any simple way, in C#, to make cmd.exe think you are a human being typing in it, so I can simulated this programmatically? Otherwise, System.Diagnostics.Process, doesn't seem to offer a way to interacted with a process that outputs a password prompt. You never get to see the prompt that clearly happens when you run the same thing in cmd.exe
cmd.exe is not the SSH client; it's just a shell for one. Explore the capabilities of the actual client. In PuTTY (very popular!) there's an autologon feature, if you have an SSH key.
You could use
Windows.Forms.SendKeys()
to send password as keystrokes
Reference Material
Without knowing which commandline tool you are using to ssh to the server, isn't there a commandline parameter to provide a password.
C:\> ssh user#ip -p password
Or have you tried input redirection:
ssh user#ip <
Yourpassword
EOF
In looking into your earlier question, what is the trouble you are having in using the programmer interface?
Are you sure you need a full fledged ssh client, or do you just want to execute a command remotely. If it is the latter you might want to check out plink.
plink.exe -ssh user#host -2 -i user.ppk -m command_line.txt
How to create the ppk file: http://theillustratednetwork.mvps.org/Ssh/Private-publicKey.html