Quantcast
Channel: SSH.NET Library
Viewing all 2955 articles
Browse latest View live

New Post: Server string is null or empty

$
0
0
can you help me understand why Session.cs is throwing an InvalidOperationException of "Server string is null or empty." when it is attempting to read the response(s) coming back from the connection attempt?
It seems this exception will always be thrown if the first line in the response is NULL or empty.
Which is happening to me.

If I remove this thrown exception and allow the full timeout on the ConnectionInfo to expire, my connection is eventually made and the server version is returned in the response.

New Post: Issue with SFTPFile methods

$
0
0
Hi All
I'm getting a Object reference not set to an instance of an object error when attempting to use any of the methods of SFTPFile (MoveTo, Delete, UpdateStatus) on multiple sftp sites.
I can successfully upload files and retrieve SFTPFile properties, but it constantly fails when trying to do any of the work.

It fails on SubsystemSession.cs line 108 SendData(byte[] data)

This is the log
SshNet.Logging Verbose: 1 : Initiating connect to '127.0.0.1:22'.
SshNet.Logging Verbose: 1 : Server version '2.0' on 'CoreFTP-0.3.2'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'KeyExchangeInitMessage': 'SSH_MSG_KEXINIT'.
SshNet.Logging Verbose: 1 : SendMessage to server 'KeyExchangeInitMessage': 'SSH_MSG_KEXINIT'.
SshNet.Logging Verbose: 1 : SendMessage to server 'KeyExchangeDhInitMessage': 'SSH_MSG_KEXDH_INIT'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'KeyExchangeDhReplyMessage': 'SSH_MSG_KEXDH_REPLY'.
SshNet.Logging Verbose: 1 : SendMessage to server 'NewKeysMessage': 'SSH_MSG_NEWKEYS'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'NewKeysMessage': 'SSH_MSG_NEWKEYS'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ServiceRequestMessage': 'SSH_MSG_SERVICE_REQUEST'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ServiceAcceptMessage': 'SSH_MSG_SERVICE_ACCEPT'.
SshNet.Logging Verbose: 1 : SendMessage to server 'RequestMessageNone': 'SSH_MSG_USERAUTH_REQUEST'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'FailureMessage': 'SSH_MSG_USERAUTH_FAILURE'.
SshNet.Logging Verbose: 1 : SendMessage to server 'RequestMessagePassword': 'SSH_MSG_USERAUTH_REQUEST'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'SuccessMessage': 'SSH_MSG_USERAUTH_SUCCESS'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelOpenMessage': 'SSH_MSG_CHANNEL_OPEN : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelOpenConfirmationMessage': 'SSH_MSG_CHANNEL_OPEN_CONFIRMATION : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelRequestMessage': 'SSH_MSG_CHANNEL_REQUEST : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelSuccessMessage': 'SSH_MSG_CHANNEL_SUCCESS : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelWindowAdjustMessage': 'SSH_MSG_CHANNEL_WINDOW_ADJUST : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelEofMessage': 'SSH_MSG_CHANNEL_EOF : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelCloseMessage': 'SSH_MSG_CHANNEL_CLOSE : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelCloseMessage': 'SSH_MSG_CHANNEL_CLOSE : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'DisconnectMessage': 'SSH_MSG_DISCONNECT'.
A first chance exception of type 'Renci.SshNet.Common.SshConnectionException' occurred in Renci.SshNet.dll
A first chance exception of type 'System.NullReferenceException' occurred in Renci.SshNet.dll
and this is the call stack
>   Renci.SshNet.dll!Renci.SshNet.Sftp.SubsystemSession.SendData(byte[] data) Line 108  C#
    Renci.SshNet.dll!Renci.SshNet.Sftp.SftpSession.SendMessage(Renci.SshNet.Sftp.SftpMessage sftpMessage) Line 84 + 0xd bytes   C#
    Renci.SshNet.dll!Renci.SshNet.Sftp.SftpSession.SendRequest(Renci.SshNet.Sftp.Requests.SftpRequest request) Line 247 + 0xd bytes C#
    Renci.SshNet.dll!Renci.SshNet.Sftp.SftpSession.RequestRemove(string path) Line 633 + 0x13 bytes C#
    Renci.SshNet.dll!Renci.SshNet.Sftp.SftpFile.Delete() Line 469 + 0x2d bytes  C#
    Ziptrek.CeridianLibrary.exe!Ziptrek.CeridianLibrary.SFTPUpload.RenameFile(string oldFileName) Line 120 + 0x16 bytes C#
    Ziptrek.CeridianLibrary.exe!ConsoleApplication1.Program.Main(string[] args) Line 35 + 0x1d bytes    C#
    [External Code] 

``` Any help i get would be greatly appreciated as its holding up a large project of mine.

New Post: Issue with SFTPFile methods

$
0
0
I'm not sure where but the problem appears to be in my code somewhere i think.
I managed to get the rename to work by using sftpClient.rename rather than File.MoveTo.

Literally just commented out File.MoveTo and replaced it with SFTPClient.Rename. Seems odd to me but i can't manage to reproduce anywhere else.

Thanks for the project. Has been very simple and stable to work with!

New Post: Permission denied (publickey)

$
0
0
Hi,
   I am using private key to connect to Unix host.
PrivateKeyFile SSHKey = new PrivateKeyFile( @"C:\x_dsa.txt" );
string userName = "user1";
PrivateKeyConnectionInfo conInfo = new PrivateKeyConnectionInfo( host, userName, SSHKey );
using ( ScpClient scp = new ScpClient( conInfo ) )
{
scp.Connect();
but it always failes with error "Permission denied (publickey)"

New Post: Dealing with "prompts"

$
0
0
Ive managed to get connected and ive manged to send commands and recieve responses so its working great so far. But whenever I execute a command that has a prompt on the next line my code simply just hangs...

Heres my code:
            PasswordAuthenticationMethod authMethod = new PasswordAuthenticationMethod(username, password);
            ConnectionInfo connectionInfo = new ConnectionInfo(session, username, authMethod);
            vms = new SshClient(connectionInfo);
            vms.Connect();

            SshCommand result = vms.RunCommand(command);
            Console.WriteLine(result.Result);
Any ideas? Its working quite well other than just hanging.

Commented Feature: Add support SSH-2 private keys [1987]

$
0
0
I need to connect using sftp utilizing private key.
The key file is created using SSH-2 client.
I get "Invalid private key file." error message.

I just want to confirm if SSH-2 keys are supported!!
if not, are you aware of any open source library that support the use of SSH-2 generated keys?
Here is how the header of the key looks like..

---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
Comment: "[2048-bit dsa,

and it ends with (showing last part of the encrypted key as well) :
sPhKT5RRC1HrFpK4GzMDgRv3+z5pRf+rPV+FT71busXPnsFIJ54t7xQcGCuzPvCS0myyMQ
AIdA==
---- END SSH2 ENCRYPTED PRIVATE KEY ----

Thank you.
Comments: ** Comment from web user: zchawla **

How can get the library of including changeset 35691

New Post: [SOLVED] Retrieving a LOT of output from a command...

$
0
0
I have figured out recently on the Cisco switches on the network I work on the "term pager 0" doesn't work.
Dim result1 As String = DoCommand(client, "enable" & vbLf & "enablePass" & vbLf & "term pager 0" & vbLf & "sh run" & vbLf)
Instead I had to use "terminal length 0" to get the same result.
Dim result1 As String = DoCommand(client, "enable" & vbLf & "enablePass" & vbLf & "term len 0" & vbLf & "sh run" & vbLf)
I hope this helps someone out. Your example is a great one for learning and has helped me get started working with this library. Tip my hat off to you!

Commented Unassigned: SftpClient is throwing undocumented exceptions [2148]

$
0
0
The documentation says that Connect can throw InvalidOperationException and ObjectDisposedException, but when you can't connect (remote server stopped, network problem, ...) a SocketException is thrown after a long timeout (about 10 seconds).

Worst, if you catch the exception and log the error another SocketException is thrown when you call Dispose. Documentation doesn't list any exceptions for Dispose.
Comments: ** Comment from web user: wwcamtig **

This is not the only case. Another example is SftpClient.Get(). It will throw SftpPathNotFoundException if the remote file doesn't exist.


Created Unassigned: Unable to execute the commands with "sudo" on CentOS-OpneLogic [2279]

$
0
0
Hi,

I was trying to access and execute the commands on remote Linux machine of CentOs-OpenLogic. But while executing the commands with sudo option, i was getting error like tty required. My code is as follows:

New-SshSessions -ComputerName <name.cloudapp.net> -Username <name> -Keyfile <path to key file>
nvoke-SshCommand -ComputerName <name.cloudapp.net> -Command "sudo mkdir testfolder"
Remove-Sshsession

The error is "sudo: sorry, you must have a tty to run sudo", but the same script is working for Ubuntu OS. I was unable to figure out what exactly the problem was.

It is an urgent issue, please anyone help me on this.

Thanks and Regards,
Bhaskar D

Created Unassigned: NullReferenceException on opening and listen to a ShellStream [2293]

$
0
0
Hello,

i am having the following issue on the newest beta version of Renci.SSHNet 2014.4.6.0

If I try to open a ShellStream on a previously opened SSH Session to an embedded Linux system I am getting the following error:

```
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
"TIM LiveLogger.vshost.exe" (CLR v4.0.30319: TIM LiveLogger.vshost.exe): "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_de_b77a5c561934e089\mscorlib.resources.dll" geladen. Das Modul wurde ohne Symbole erstellt.
Eine Ausnahme (erste Chance) des Typs "System.NullReferenceException" ist in XXXXXXX.exe aufgetreten.
```

I created the session from the main thread by a click on a Windows Forms Button:

```
this.ssh_session = new SshClient(this.host, this.port, this.user, this.password);

this.ssh_session.Connect();

this.shell = ssh_session.CreateShellStream("TEST", 0, 0, 0, 0, 0);

this.shell.DataReceived += new EventHandler<Renci.SshNet.Common.ShellDataEventArgs> his.shell_DataReceived);
this.shell.ErrorOccurred += new EventHandler<Renci.SshNet.Common.ExceptionEventArgs>(this.shell_ErrorOccurred);
```

New Post: ShellStream, end of command / waiting for input

$
0
0
@washirv,

The short answer is "Yes." You can look for a prompt, and/or apply a timeout. You can even extend and write your own, which others have done.

Many have posted working examples in these discussion groups, and you can even look at (or compile if you like) the source code tests (something I never do when I write, I'm ashamed to say), which you can find here.

As you can see by the source, it is an extremely large and comprehensive effort, and one with an interesting history. When you get something working well, please think about posting it in the discussions. Who knows? It might make it into some more formal docs in future! :)

pat
:)

New Post: Dealing with "prompts"

$
0
0
@Jelly,

There are many examples from the users here in the discussions to do all kinds of things. There is certainly an example in the discussions, docs, or tests/source to do with what you are trying to get working.

But there are a myriad of things not involved with the SSH library that could be in your way. I mean, one thing could easily be that you are talking to a router or server that requires a CR, LF, or CRLF in order to get your commands. Also, ssh needs to know when the other side is 'done'. As another poster asked, you can do this with a timer, the stream not growing after x time, a timeout, etc.

I wrote a wrapper a while back that reset a timer to 0 whenever there was activity on the stream. If the timer expired, it meant that I wasn't going to wait any longer for any more data, and I proceeded with what I got to that point.

What debugging have you done to see (maybe even on the host) what it might be expecting next, or if it has even given up?

I'm just trying to say, that it is actually more complicated to logon & do commands than most people (me included) realize. That of course means a lot more places to go wrong! :)

So when it works, nobody says anything, but when it fails...!

So if you can provide a bit more detail on the environment, logs/debugging, and pinpointing the place at which the thing breaks down, it makes it a lot easier to offer help. Right now, the code above might just work for me, but I'd be running it on a host not like yours... :)

Not trying to be depressing, just hoping to get more info about your issue! :)

code is poetry.

pat
:)

New Post: [SOLVED] Retrieving a LOT of output from a command...

$
0
0
@chipgraphics,

What a nice note!

Thanks!

It was a stupid change for cisco, and makes no sense whatsoever... it's the same IOS, for cryin' out loud...

New Post: Server String is null or empty

$
0
0
I have an SSIS (SQL Server Integration Services) package that is c# based. I am trying to connect to a MySQL server using the SSH Renci library. Here is what I am trying:

using Renci.SshNet.Common;
using Renci.SshNet;

SshClient client;

client = new SshClient("123.45.3.45", 3306, "MyName", "MyPassword");
client.Connect();

I get an error: Server string is null or empty. Below is the full message.

I have three hairs left on my head and would like to salvage the remaining strands. Any help is greatly appreciated!

Error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Server string is null or empty.
at Renci.SshNet.Session.Connect()
at Renci.SshNet.BaseClient.Connect()
at ST_4cdf908771f54364870e08c182e0ce4d.csproj.ScriptMain.Main()
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript()

Created Unassigned: SshCommand doesn't cleanup subscribed events [2295]

$
0
0
The SshCommand class leaves the unerlying channel subscribed to the session events after running a command.

Repro is:
```
using (var client = new SshClient(connectionInfo))
{
client.Connect();

for (var i = 0; i < 100; ++i)
{
// Inspect client.Session.ErrorOccured.GetInvocationList()
using (var cmd = client.CreateCommand("echo hi"))
{
cmd.Execute();
}
// Inspect client.Session.ErrorOccured.GetInvocationList()
// Invocation list is one greater than before.
}
var after = GetEventCount(client);
Assert.AreEqual(before, after);
}
```

It looks like the bug is in SshCommand.EndExecute where this._channel is set to null without being disposed. A proposed fix is attached.

Commented Unassigned: SftpClient is throwing undocumented exceptions [2148]

$
0
0
The documentation says that Connect can throw InvalidOperationException and ObjectDisposedException, but when you can't connect (remote server stopped, network problem, ...) a SocketException is thrown after a long timeout (about 10 seconds).

Worst, if you catch the exception and log the error another SocketException is thrown when you call Dispose. Documentation doesn't list any exceptions for Dispose.
Comments: ** Comment from web user: hmflash **

The exception thrown by dispose happens any time connect fails. Attached is a patch to correct this behavior.

Commented Unassigned: NullReferenceException on opening and listen to a ShellStream [2293]

$
0
0
Hello,

i am having the following issue on the newest beta version of Renci.SSHNet 2014.4.6.0

If I try to open a ShellStream on a previously opened SSH Session to an embedded Linux system I am getting the following error:

```
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : SendMessage to server 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
SshNet.Logging Verbose: 1 : ReceiveMessage from server: 'ChannelDataMessage': 'SSH_MSG_CHANNEL_DATA : #0'.
"TIM LiveLogger.vshost.exe" (CLR v4.0.30319: TIM LiveLogger.vshost.exe): "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_de_b77a5c561934e089\mscorlib.resources.dll" geladen. Das Modul wurde ohne Symbole erstellt.
Eine Ausnahme (erste Chance) des Typs "System.NullReferenceException" ist in XXXXXXX.exe aufgetreten.
```

I created the session from the main thread by a click on a Windows Forms Button:

```
this.ssh_session = new SshClient(this.host, this.port, this.user, this.password);

this.ssh_session.Connect();

this.shell = ssh_session.CreateShellStream("TEST", 0, 0, 0, 0, 0);

this.shell.DataReceived += new EventHandler<Renci.SshNet.Common.ShellDataEventArgs> his.shell_DataReceived);
this.shell.ErrorOccurred += new EventHandler<Renci.SshNet.Common.ExceptionEventArgs>(this.shell_ErrorOccurred);
```
Comments: ** Comment from web user: bernieserver **

Ok, i found the error. It was my fault.

I forgot to catch an exception inside the DataReceived handler.

My Exception (it was a non - opened filestream to write console output into) was fallen through the whole MessageListener of Renci.SSHNet.

```
private void MessageListener()
{
try
{
while (this._socket != null && this._socket.Connected)
{
var message = this.ReceiveMessage();

if (message == null)
{
throw new NullReferenceException("The 'message' variable cannot be null");
}

this.HandleMessageCore(message);
}
}
catch (Exception exp)
{
// MY EXCEPTION IS FALLEN THROUGH TO HERE!
this.RaiseError(exp);
}
}
```

Thank you!

Regards
Bernhard

New Post: Dealing with "prompts"

$
0
0
Hello Pat,

Thanks for taking the time to look into my problem. I agree theres lots of good information on here and i'm getting little bits from here and there, but im at a stage now where I think I just need the gentle nudge in the right direction.

So here's the situtation... We are using a system called OpenVMS. What i'm attempting to do is to create an automation test suite in C#, its going well so far but everyone still has to manually run batch jobs in openVMS to complete the financial transactions. I dont like having manual steps in my tests! :)

So far i've been able to send commands and read responses no problem, the only issue is when theres a prompt. The issue isnt detecting the prompt I can do that easily its then dealing with the prompt... let me show you my code..
        string myCommand = command;
        myCommand = myCommand.TrimEnd();
        TimeSpan commandTime;
        Stopwatch stopwatch = new Stopwatch();
        string result = "";
        string output = "";
        var cmd = client.CreateCommand(myCommand);

        try
        {
            stopwatch.Start();
            var asynch = cmd.BeginExecute();
            var resultStream = new StreamReader(cmd.OutputStream);

            while (!asynch.IsCompleted)
            {
                commandTime = stopwatch.Elapsed;
                if (commandTime > timeOut)
                {
                    break;
                }
                result = resultStream.ReadToEnd();
                output = output + result;
                Debug.WriteLine(result);
            }
            cmd.CancelAsync();
            cmd.EndExecute(asynch);
            resultArray = output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            WebDriver.myLogger.LogComment("Class: " + MethodBase.GetCurrentMethod().DeclaringType.FullName);
            WebDriver.myLogger.LogComment("Method: " + MethodBase.GetCurrentMethod().Name);
            WebDriver.myLogger.LogPass("Executed VMS command: " + myCommand);
        }
        catch (Exception ex)
        {
            WebDriver.myLogger.LogComment("Class: " + MethodBase.GetCurrentMethod().DeclaringType.FullName);
            WebDriver.myLogger.LogComment("Method: " + MethodBase.GetCurrentMethod().Name);
            WebDriver.myLogger.LogFail("Error executing VMS command: " + myCommand + " | " + ex.Message);
        }
        WebDriver.TestLog().LogStep(WebDriver.TestLog().GetTestResult(), "Execute command");


What I need to be able to do is when i detect the prompt... somewhow change my command "cmd" to something like "Text\R" which would input text and a return...
ive not yet worked out how to do this yet because it wont build if i try. I thought maybe I could just cancel the command when it hits the prompt and create a new one, and execute that, but that doesnt work either.

I'm sorry if im not explaining this very clearly, as I said I know how to detect the prompts thats not an issue I just need some way of dealing with them.

In OpenVMS we have DCL's (Digital Command Language) I can use this to run whats known as an ARL (Advanced Reporting Language) and I can do this by creating a text file, filling it with the parameters and then basically saying okay VMS run this ARL and use this text file as your input....Im wondering if I can do that with this? Send a command with a list of parameters to use when it detects prompts....

New Post: How to get command result which contains multiple lines...

$
0
0
You could use an array..

String[] myArray = cmd1.Result.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

This will split the array based on carriage returns and new lines etc

New Post: Dealing with "prompts"

$
0
0
@Festive,

I no longer do things this way, because on the systems I am programming against today (Cisco switches, routers, & ASAs), the command prompt is the last thing output after a command. You make it sound like the return string(s) are asynchronous, and the ssh term will see the command prompt returned before the last of the response from the host.

That said, you can monitor text as it is returned, and simply RegEx or .Contains() each batch as they are added into the response as a whole. I have written a 'chunking' wrapper for my commands, as the hosts I'm programming against have a 1kB limit on the command length, and I may need to give 1000's of lines of commands in a single 'action', or 'batch'. My code got complicated quickly as the Cisco equipment will allow multiple sessions from the same user, but the client would not allow multiple SSH/22 connections to the same host-and my program is very multi-threaded.

One thing nobody on SO could solve was how to have multiple threads submit 'work', or 'jobs' as ssh commands, process each serially (one at a time), then (hard part) return the results to each calling thread. That took me a while to get right, and we'll talk about that another day! :)

So let me start with the smallest denominator in my rather complicated system (intuitively called, "SendBigCommand"):

Note: You can convert easily, but VB proves much easier to use and troubleshoot than C#, and the event/regex processing makes it easy to return to your code months later when it is unrecognizable).

[Yes, I write in both, and Java, and Perl, and... so no nasty comments; Just using the right tool for the job]

Public Function SendBigCommand(TheCommands As String, Optional IdleTimeout As Integer = 4) As String
        Dim tsIdleTimeout As TimeSpan = TimeSpan.FromSeconds(IdleTimeout)
        Dim swIdleTimeout As New Stopwatch
        Dim sbResult As New StringBuilder
        Dim sResult As String = ""
        '
        Try
            Using c As SshClient = New SshClient(Me.Host, Me.User, Me.Pass)
                c.Connect() ' only ONE thread can connect at a time!
                If c.IsConnected Then
                    '
                    ' since each command starts from scratch, we need to always get to #enable before we enter the submitted commands...
                    '
                    Dim sGetToEnable As String = "enable" & vbLf & Me.EnablePass & vbLf & "term pager 0" & vbLf
B Dim cmdLastLine As String = Me.GetLastLine(TheCommands)
                    '
                    Dim cmdCombined As String = String.Concat(sGetToEnable, TheCommands & vbLf)
                    log.Debug("cmdCombined: [" & cmdCombined & "]")
                    '
                    Using cmd As SshCommand = c.CreateCommand(cmdCombined)
                        Dim cmdIndex = cmdCombined.IndexOf(cmdLastLine)
                        Dim asynch As System.IAsyncResult = cmd.BeginExecute()
                        Using reader As StreamReader = New StreamReader(cmd.OutputStream)
                            Dim res As String = ""
                            swIdleTimeout.Start()
                            Do While Not asynch.IsCompleted
                                res = reader.ReadToEnd()
                                If String.IsNullOrEmpty(res) Then
                                    If swIdleTimeout.Elapsed.TotalSeconds >= tsIdleTimeout.TotalSeconds Then
                                        log.Debug(String.Format("Exiting from async execution.. idle for {0} seconds", swIdleTimeout.Elapsed.TotalSeconds.ToString("0.00")))
                                        ' cmd.CancelAsync() ' turns asynch.IsCompleted to True; same as doing: (not really, throws exception)
                                        Exit Do
                                    End If
                                    Continue Do
                                Else
                                    sbResult.Append(res)
                                    swIdleTimeout.Restart() ' every time we get something, we re-start the timer...
                                End If
                            Loop
                            ' here after IdleTimeout _or_ rare asynch.IsCompleted()
                        End Using
                        '
                        '=========================================================
                        '
                        ' return anything after the last line of the command (cmdLastLine)
                        '
                        sResult = sbResult.ToString ' convert SB into string
                        log.Debug("sResult: Before [" & sResult & "]")
                        log.Debug("cmdLastLine: " & cmdLastLine)
                        log.Debug("cmdLastLine.Length: " & cmdLastLine.Length)
                        '
                        ' try to remove everything up to the actual response...
                        '
A Dim indexOfLastCharOfCommand As Integer = sResult.IndexOf(cmdLastLine) + cmdLastLine.Length
| '
| ' final string result (sResult):
| '
A sResult = sResult.Substring(indexOfLastCharOfCommand, sResult.Length - indexOfLastCharOfCommand)
                        log.Debug("sResult: After [" & sResult & "]")
                        '
                    End Using
                Else
                    log.Fatal("client could not connect!")
                    Throw New Exception("Client could not connect")
                End If
            End Using
        Catch ex As Exception
            log.Fatal("EXCEPTION(M): " & ex.Message)
            log.Fatal("EXCEPTION(T): " & ex.ToString)
            log.Fatal("EXCEPTION(S): " & ex.StackTrace)
        End Try
        Return sResult
    End Function
I hope this isn't too intimidating. It evolved over time. :)

The observant will notice that (1) I'm not concerning myself with a prompt, and (2) the line: _" ' here after IdleTimeout or rare asynch.IsCompleted()"_ This is because in my situation, I simply NEVER get a signal asynch.IsCompleted-never have. I gave up and moved on by allowing a integer timeout (ToSeconds) that the calling function can set (big commands don't take a lot more than small ones, as it is just idle timeout, not whole operation timeout).

Let em explain the parts that aren't included in the function. The first is GetLastLine(), (B) which I use to trim the response (in my case, the responses include the commands as entered, which is why you see the lines at the A-A. I don't want to process the commands, just the results.
        Public Function GetLastLine(SomeLines As String) As String 
            Dim linesNL() As String
            linesNL = SomeLines.Split(CChar(Environment.NewLine))
            Dim linesLF() As String
            linesLF = SomeLines.Split(CChar(vbLf))
            Dim linesCR() As String
            linesCR = SomeLines.Split(CChar(vbCr))
            Dim linesCRLF() As String
            linesCRLF = SomeLines.Split(CChar(vbCrLf))
            ' each is an array:
            Dim linesArrayArray As String()() = {linesNL, linesLF, linesCR, linesCRLF}

            Dim largest As Integer = linesArrayArray.Max(Function(ar) ar.Count)
            log.DebugEx("largest: {0}", largest)
            ' now which array had than many lines?

            Dim descArray = linesArrayArray.OrderByDescending(Function(c) c.Count)
            log.DebugEx("descArray(0).Count is {0}", descArray(0).Count)
            log.DebugEx("descArray(1).Count is {0}", descArray(1).Count)
            log.DebugEx("descArray(2).Count is {0}", descArray(2).Count)
            log.DebugEx("descArray(3).Count is {0}", descArray(3).Count)

            Dim longestArray As String() = {}

            'For Each element As Integer In numLines
            '    large1 = Math.Max(largest, element)
            'Next

            Dim lastLine As Integer = descArray(0).Count
            Return descArray(0)(lastLine - 1)
        End Function
Now before you guys start laughing, this is how I solved the problem of not knowing whether the commands are given (or even mixed) as nothing, LF, CR, or CRLF at the end of each line. Welcome to Cisco IOS...

That is why you see this above:
Dim linesArrayArray As String()() = {linesNL, linesLF, linesCR, linesCRLF}
You find a better way, I'm all ears!

Suggestion

In the above SendCommand, you will see the following lines:
[...]
Else
    sbResult.Append(res)
    swIdleTimeout.Restart() ' every time we get something, we re-start the timer...
End If
[...]
Every time I am there, it means that a line of test/string (var res) has gobbled up some response. Becuase of this activity, the command swIdleTimeout.Restart() does what it says, and resets the idle timer.

So this is the perfect place to do regex on the last text received from the host (might be multi-line, so prepare for that?), using the string variable 'res' (in my case). If you regex res, and you see a match for your command prompt, or whatever, then you can trigger another action, flip a boolean and wait, or even redirect the output, etc.

Knowing what little I do about your issue, and selecting only fro the code I have written, this seems a good mechanism to inspect the host response as it is coming back to the client. Now be mindful, your host might return ALL of your data from a command in one big string, or it may give it to you line-by-line... Ebanle lots of debugging to see.

Note On Code: I tried to remove as much comments/etc. for clarity.
Viewing all 2955 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>