I need to send a list of commands to several devices. For each IP, open an SSH-connection with the given credentials from User and Password textboxes, run all of the commands and return the output to the Output textbox.
Normally I'd use
plink.exe -ssh admin@172.16.17.18 -pw PassW0rd "command"
Unfortunately, the remote host does not let me do that:
Sent password
Access granted
Opening session as main channel
Opened main channel
Server refused to start a shell/command
FATAL ERROR: Server refused to start a shell/command
However, if I connect without handing over a command:
Sent password
Access granted
Opening session as main channel
Opened main channel
Allocated pty (ospeed 38400bps, ispeed 38400bps)
Started a shell/command
Welcome to XXX
System_Name>#
Now, I can type my commands and have them executed. I tried PoshSSH, which lets me connect but any command times out.
I broke down the lines from the IP- and Command-boxes into string-arrays and made for loops. Then I tried several approaches with Start-Job
and SystemDiagnostics.Process*
without success.
Now I'm a bit clueless and would appreciate any help:
for ($a=0; $a -lt $IPArray.Length; $a++){
# Open an interactive Session with plink like
# plink.exe -ssh ' + $User + '@' + $IPArray[$a] + ' -pw ' + $Passwd
for ($b=0; $b -lt $CommandArray.Length; $b++){
# Send $CommandArray[$b] to plink-Session
# Wait for command to finish
# Read output and send it to the textbox
}
}
Edit: Thanks to Martin Prikryl's answer I'm a step further:
for ($a=0; $a -lt $IPArray.Length; $a++){
$User = $UserTextBox.text
$IP = $IPArray[$a]
# $Passwd = $PwdTextBox.Text
$Outputtext= $Outputtext + "~~~~~ " + $IP + " ~~~~~" + "`r`n"
$isSession = New-SSHSession -ComputerName $IP -Credential $User
$isStream = $isSession.Session.CreateShellStream("PS-SSH", 0, 0, 0, 0, 1000)
for ($b=0; $b -lt $CommandArray.Length; $b++){
$Command = $CommandArray[$b]
$isStream.WriteLine("$Command")
Start-Sleep -Seconds 1
}
$isReturn = $isStream.Read()
$Outputtext= $Outputtext + $isReturn + "`r`n"
$outputBox.Text = $Outputtext
}
returns:
~~~~~ 172.16.17.18 ~~~~~
Welcome to XXX
System_18>#echo 1
1
System_18>#echo 2
2
System_18>#ping 8.8.8.8
PING 8.8.8.8 56 data bytes
~~~~~ 172.16.17.19 ~~~~~
Welcome to XXX
System_19>#echo 1
1
System_19>#echo 2
2
System_19>#ping 8.8.8.8
PING 8.8.8.8 56 data bytes
~~~~~ 172.16.17.20 ~~~~~
Welcome to XXX
System_20>#echo 1
1
System_20>#echo 2
2
System_20>#ping 8.8.8.8
PING 8.8.8.8 56 data bytes
Now I need to achieve two things:
Get the credentials from the corresponding input fields (Currently, I need to type in the password once for each IP)
Done:
$User = $UserTextBox.text
$Passwd = ConvertTo-SecureString $PwdTextBox.Text -AsPlainText -Force
$SSHCred = New-Object System.Management.Automation.PSCredential -ArgumentList ($User, $Passwd)
# ...
$isSession = New-SSHSession -ComputerName $IP -Credential $SSHCred
Make it wait for a command to finish, before sending the next one. (Currently, it just waits 1 second)
However, I'm happy that the remote hosts now talk to me, at least. Thank you.
Should I open new questions, if I need further help with the script or continue to log the progress, here?
You are obviously connecting to some "device", not a full server. Embedded SSH implementations usually do not implement SSH "exec" channel. You have to use "shell" channel (what is otherwise not recommended for command automation).
With Plink you can achieve that by writing the "command" to Plink input, instead of using the -m
switch.
See also Executing command using Plink does not work, but does in PuTTY.
Though you should not run an external application to implement SSH. Use a native .NET SSH implementation, like SSH.NET. Pseudo code to execute command with SSH.NET in "shell" channel:
var client = new SshClient(...);
client.Connect();
var shell = client.CreateShellStream(...);
shell.WriteLine("command");
var output = shell.Read();
The "shell" channel is a black box with an input and an output. There is no reliable way to use it to execute a command, read its output, and execute other commands. You have no API to tell when a command execution has ended. That is why I wrote above that the "shell" channel is not recommended for command automation. All you can do is to parse the shell output and look for your device's command prompt: System_20>
.