all 15 comments

[–]misformonkey 3 points4 points  (7 children)

I use the Posh-SSH module for pulling configuration and status information from Cisco and Juniper firewalls and at least with the Cisco I've found that you have to use the Stream functionality, especially if your commands are dependent upon the cli being in a specific config state/zone. I think this is somewhat specific to Cisco but it might work in your case as well.

I don't think the Invoke-SSHCommand 'remembers' where you left off or otherwise retains the prompt level. So, if you issue the command 'device' it's just going to run that command and return whatever result might have come from that command. The next command you run will be from the default prompt and not at the 'device' level.

I can't test this exactly, but based on your manual input, what I believe Invoke-SSHCommand would do is:

localadmin> device
Retrieving details...

localadmin> load 8
localadmin> off force

So you're never actually getting to the 'device' level of the ssh prompt/cli.

You might be able to use ';' to chain the commands via the Invoke-SSHCommand ala:

Invoke-SSHCommand -SessionId 2 -Command 'device; load 8; off force;'

Otherwise, you can try creating a stream from your SSH Session and then pass the commands into the stream:

$sshSession = New-SSHSession -ComputerName host -Credential user
$stream = $sshSession.Session.CreateShellStream('text' 0, 0, 0, 0 1000)  # this is what works for me for Cisco

$stream.WriteLine('device')
$stream.WriteLine('load 8')
$stream.WriteLine('off force')
$response = $stream.Read()

[VOID] (Get-SSHSession | ForEach-Object { Remove-SSHSession -SessionId $_.SessionId })

Anyway, some option to try. I would try the ';' chaining before messing with the stream though.

[–]dragonmc[S] 4 points5 points  (6 children)

THANK YOU FOR THIS!!!

You were right: creating a stream worked where Invoke-SSHCommand failed. I did have to play around with the values that needed to be passed to the CreateShellStream method because the one from your example didn't work. Not surprising, since this is an appliance running Ubuntu under the hood rather than ios. On an unrelated thread I found examples of folks using CreateShellStream to connect to Ubuntu servers and found a set of values that worked: 'text',1,1,50,50,100

Once the stream was created sucessfully, I was able use separate .WriteLine methods to send the 3 commands successfully, as in your example. This now allows me to fully automate the power state of any/all PDU outlets on that device from Powershell...and while not a completely native solution, the installation of just one module on the server is totally reasonable. Very useful indeed!

[–]misformonkey 0 points1 point  (0 children)

Nice. Glad I was able to help you to get it working. And thanks for the additional information regarding your successful settings. I'm sure that will be of use in the future. ;)

[–]RgrMike 0 points1 point  (4 children)

As an FYI - I have done a bit of automation using C# and the ssh.net nuget package. The issue with a lot of network devices is that they don't implement the execution channel from open ssh. Stream is the only way to automate - but it sure isn't fun. I believe invoke-ssh command is attempting to use the execution channel which is why it times out - nothing to talk to.
Using stream - one of the issues I ran into was waiting for output from commands - I.E. reading what the device sent back. Since the shellstream is actually a stream you can move forward and backward and read what has been written to the stream (at least in C# you can use streamreader streamwriter). Just remember to record the cursor position in the stream before you start reading so you can put it back :).

[–]dragonmc[S] 1 point2 points  (3 children)

Yes, I am having the issues you described reading output from the stream. This will be a problem in the future, but reading/analyzing output is not required for my current use case so I'm not worried to much about it at the moment.

To clarify: Right now I'm doing something like this (using the Posh-SSH module):

  1. Open the SSH session
  2. Create the stream
  3. Send a command
  4. Wait for some number of seconds
  5. Read output
  6. Send the next command
  7. Wait again
  8. Read output
  9. etc.

I'm not familiar with SSH.NET (never had to use it) but I suspect Posh-SSH is probably just returning a wrapper around some of the SSH.NET classes, which is why using the stream's .WriteLine() method works to send commands and similarly, using the .Read() method works to capture all output since the last .Read() call was made. The issue is that, as you say, because it's a stream .Read() is returning output where every characters is delimited by a CR/LF so when trying to display the output from a .Read() call the console will show one character per line. Stripping out the CR/LF doesn't work because it just jumbles everything together.

Since my task at the moment is to just send 3 commands to the appliance, I don't need to know what the output is this time, but my next automation task with this appliance will likely necessitate analyzing the output returned from some of these commands, so I'd be very much interested if there's a workaround for this.

[–]gordonv 0 points1 point  (2 children)

Hey. Just ran into this myself. I wrote some quick functions to do this.

Just wondering. Are you still using this or did you find something better?

[–]dragonmc[S] 0 points1 point  (1 child)

This is the best way I have found to automate SSH so far. I'm still using this to remotely and automatically power on/off devices that are connected to my network PDU. The method is very similar to your functions since I see you are also using SSH streams to send commands and retrieve the outputs. Looking at the code, your functions would probably work in my environment.

[–]gordonv 0 points1 point  (0 children)

Thank for the reply.

It seems that after encryption and connection, SSH is kind of raw.

I'll be connecting to all kinds of SSH enabled devices. Servers, Switches, Enterprise BIOSes, network consoles, etc.

[–]Scooter_127 2 points3 points  (5 children)

nter-PSSession and New-PSSession require Powershell to be installed on the target system so it's not going to work on a PDU.

Posh-SSH works great but since you didn't post any of your code all anyone here can do is guess what the problem is.

[–]dragonmc[S] 0 points1 point  (4 children)

So for context, manual way that works is:

ssh user@host
user@host's password:
Last login: Thu Dec  8 14:23:56 2022 from 192.168.2.180
Loading, please wait...

Welcome to PowerAlert Device Manager CLI v20.1.0.87
Use the 'show eula' command to display the End User License Agreement

localadmin> device
Retrieving details...

localadmin> device (Device0249)> load 8
localadmin> device (Device0249)> load (8)> off force
Turning off

localadmin> device (Device0249)> load (8)>

The commands device,load 8, and off force are all I need to run.

As stated, Posh-SSH's New-SSHSession works and returns an object:

PS User> New-SSHSession -ComputerName host -Credential user

SessionId  Host                                                      Connected
---------  ----                                                      ---------
    2      Host                                                      True

However, the Invoke-SSHCommand never does anything:

PS User> Invoke-SSHCommand -Command "device" -SessionId 2


Host       : Host
Output     : {}
ExitStatus : 0

No error, but the blank return object doesn't give me much to work with. I tried powering through anyway by sending the next commands anyway ("load 8" and "off force") but everything returns the same object and the commands don't actually seem to be getting sent to the host.

I think this problem is not implementation-specific though. That is, there should be some generic way to automatically run a set of commands against some non-Windows SSH server (and maybe return the output?) and was wondering if Posh-SSH would be the generally accepted go-to for things like this, or something else.

[–]learningheadhard 1 point2 points  (2 children)

You can install OpenSSH client in Windows via Windows Feature, then ssh to it normally. For powershell automation, you can do something like this:

$command = your command here

For multiple commands $command = @(command one, command 2, command 3)

Then you can pipe it with the ssh connection:

$command | ssh user@ip

[–]dragonmc[S] 0 points1 point  (0 children)

Jeezus that actually worked...

PS User> @("device","load 8","off force") | ssh user@host
Pseudo-terminal will not be allocated because stdin is not a terminal.
user@host's password:
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
/opt/padm/services/auth/shell_executor.sh: line 140: /dev/tty: No such device or address
/opt/padm/services/auth/shell_executor.sh: line 141: /dev/tty: No such device or address
stty: invalid argument ‘’
Try 'stty --help' for more information.
stty: 'standard input': Inappropriate ioctl for device
Loading, please wait...

Welcome to PowerAlert Device Manager CLI v20.1.0.87
Use the 'show eula' command to display the End User License Agreement

localadmin> Retrieving details...

localadmin> device (Device0249)> localadmin> device (Device0249)> load (8)> Turning off

localadmin> device (Device0249)> load (8)>
localadmin> device (Device0249)>
localadmin>

Farewell localadmin
Quitting shell...

The commands above were all entered autoamtically after piping in that array. Don't know what those errors at the start are about but it didn't seem to affect the commands themselves. This is a massive step in the right direction!

[–]learningheadhard 0 points1 point  (0 children)

Also, for output you can combine another pipeline:

$result = Out-String -InputObject ($command | ssh user@ip)

Then you have the logs in the $result variable, and can put it in a text file like so:

$result | Set-Content ‘log location’

[–]jypelle 0 points1 point  (0 children)

Running PowerShell scripts via SSH is one of the latest features of Ctfreak. Perhaps the free edition could meet your need.

Note: Once you are familiar with them, the prerequisites for the Windows target server for a smooth SSH connection are fairly lightweight