Putty as an interface between cmd and sh - linux

What do I have:
a local Windows machine and a remove Linux server
a cmd script and an sh script on the local machine
a specific restriction to keep no scripts on the remote machine
What do I need:
the local cmd script to start an SSH client with specified parameters (ip:port, username#password), with that client executing the local sh script on the remote machine and passing the output back to the local machine, to the cmd script's STDOUT
Example:
whatever.cmd:
#echo off
client.exe -ip 192.168.1.1 -port 22 -username notroot -password mypwd -exec remote.sh >192.168.1.1_media.txt
Alternatively, if I convert the sh script to a set of commands sepated by ; symbol, the example may look like this:
#echo off
client.exe -ip 192.168.1.1 -port 22 -username notroot -password mypwd -command 'head `ps -aux`;df -h | grep media' >192.168.1.1_media.txt
Is there an SSH client that can be run in this way? If not, how can I make Putty do the job without using GUI?

Maybe plink is something for you. It is like putty but instead of keyboard and screen as input and output you can use pipes for input and output.
This way you can echo the lines of your script to the server.
Plink is downloadable at the putty site: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
There is also an extensive and detailed manual on that site.

Related

Running bash script over SSH [duplicate]

I have to run a local shell script (windows/Linux) on a remote machine.
I have SSH configured on both machine A and B. My script is on machine A which will run some of my code on a remote machine, machine B.
The local and remote computers can be either Windows or Unix based system.
Is there a way to run do this using plink/ssh?
If Machine A is a Windows box, you can use Plink (part of PuTTY) with the -m parameter, and it will execute the local script on the remote server.
plink root#MachineB -m local_script.sh
If Machine A is a Unix-based system, you can use:
ssh root#MachineB 'bash -s' < local_script.sh
You shouldn't have to copy the script to the remote server to run it.
This is an old question, and Jason's answer works fine, but I would like to add this:
ssh user#host <<'ENDSSH'
#commands to run on remote host
ENDSSH
This can also be used with su and commands which require user input. (note the ' escaped heredoc)
Since this answer keeps getting bits of traffic, I would add even more info to this wonderful use of heredoc:
You can nest commands with this syntax, and that's the only way nesting seems to work (in a sane way)
ssh user#host <<'ENDSSH'
#commands to run on remote host
ssh user#host2 <<'END2'
# Another bunch of commands on another host
wall <<'ENDWALL'
Error: Out of cheese
ENDWALL
ftp ftp.example.com <<'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH
You can actually have a conversation with some services like telnet, ftp, etc. But remember that heredoc just sends the stdin as text, it doesn't wait for response between lines
I just found out that you can indent the insides with tabs if you use <<-END!
ssh user#host <<-'ENDSSH'
#commands to run on remote host
ssh user#host2 <<-'END2'
# Another bunch of commands on another host
wall <<-'ENDWALL'
Error: Out of cheese
ENDWALL
ftp ftp.example.com <<-'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH
(I think this should work)
Also see
http://tldp.org/LDP/abs/html/here-docs.html
Also, don't forget to escape variables if you want to pick them up from the destination host.
This has caught me out in the past.
For example:
user#host> ssh user2#host2 "echo \$HOME"
prints out /home/user2
while
user#host> ssh user2#host2 "echo $HOME"
prints out /home/user
Another example:
user#host> ssh user2#host2 "echo hello world | awk '{print \$1}'"
prints out "hello" correctly.
This is an extension to YarekT's answer to combine inline remote commands with passing ENV variables from the local machine to the remote host so you can parameterize your scripts on the remote side:
ssh user#host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'
# commands to run on remote host
echo $ARG1 $ARG2
ENDSSH
I found this exceptionally helpful by keeping it all in one script so it's very readable and maintainable.
Why this works. ssh supports the following syntax:
ssh user#host remote_command
In bash we can specify environment variables to define prior to running a command on a single line like so:
ENV_VAR_1='value1' ENV_VAR_2='value2' bash -c 'echo $ENV_VAR_1 $ENV_VAR_2'
That makes it easy to define variables prior to running a command. In this case echo is our command we're running. Everything before echo defines environment variables.
So we combine those two features and YarekT's answer to get:
ssh user#host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'...
In this case we are setting ARG1 and ARG2 to local values. Sending everything after user#host as the remote_command. When the remote machine executes the command ARG1 and ARG2 are set the local values, thanks to local command line evaluation, which defines environment variables on the remote server, then executes the bash -s command using those variables. Voila.
<hostA_shell_prompt>$ ssh user#hostB "ls -la"
That will prompt you for password, unless you have copied your hostA user's public key to the authorized_keys file on the home of user .ssh's directory. That will allow for passwordless authentication (if accepted as an auth method on the ssh server's configuration)
I've started using Fabric for more sophisticated operations. Fabric requires Python and a couple of other dependencies, but only on the client machine. The server need only be a ssh server. I find this tool to be much more powerful than shell scripts handed off to SSH, and well worth the trouble of getting set up (particularly if you enjoy programming in Python). Fabric handles running scripts on multiple hosts (or hosts of certain roles), helps facilitate idempotent operations (such as adding a line to a config script, but not if it's already there), and allows construction of more complex logic (such as the Python language can provide).
cat ./script.sh | ssh <user>#<host>
chmod +x script.sh
ssh -i key-file root#111.222.3.444 < ./script.sh
Try running ssh user#remote sh ./script.unx.
Assuming you mean you want to do this automatically from a "local" machine, without manually logging into the "remote" machine, you should look into a TCL extension known as Expect, it is designed precisely for this sort of situation. I've also provided a link to a script for logging-in/interacting via SSH.
https://www.nist.gov/services-resources/software/expect
http://bash.cyberciti.biz/security/expect-ssh-login-script/
ssh user#hostname ". ~/.bashrc;/cd path-to-file/;. filename.sh"
highly recommended to source the environment file(.bashrc/.bashprofile/.profile). before running something in remote host because target and source hosts environment variables may be deffer.
I use this one to run a shell script on a remote machine (tested on /bin/bash):
ssh deploy#host . /home/deploy/path/to/script.sh
if you wanna execute command like this
temp=`ls -a`
echo $temp
command in `` will cause errors.
below command will solve this problem
ssh user#host '''
temp=`ls -a`
echo $temp
'''
If the script is short and is meant to be embedded inside your script and you are running under bash shell and also bash shell is available on the remote side, you may use declare to transfer local context to remote. Define variables and functions containing the state that will be transferred to the remote. Define a function that will be executed on the remote side. Then inside a here document read by bash -s you can use declare -p to transfer the variable values and use declare -f to transfer function definitions to the remote.
Because declare takes care of the quoting and will be parsed by the remote bash, the variables are properly quoted and functions are properly transferred. You may just write the script locally, usually I do one long function with the work I need to do on the remote side. The context has to be hand-picked, but the following method is "good enough" for any short scripts and is safe - should properly handle all corner cases.
somevar="spaces or other special characters"
somevar2="!##$%^"
another_func() {
mkdir -p "$1"
}
work() {
another_func "$somevar"
touch "$somevar"/"$somevar2"
}
ssh user#server 'bash -s' <<EOT
$(declare -p somevar somevar2) # transfer variables values
$(declare -f work another_func) # transfer function definitions
work # call the function
EOT
The answer here (https://stackoverflow.com/a/2732991/4752883) works great if
you're trying to run a script on a remote linux machine using plink or ssh.
It will work if the script has multiple lines on linux.
**However, if you are trying to run a batch script located on a local
linux/windows machine and your remote machine is Windows, and it consists
of multiple lines using **
plink root#MachineB -m local_script.bat
wont work.
Only the first line of the script will be executed. This is probably a
limitation of plink.
Solution 1:
To run a multiline batch script (especially if it's relatively simple,
consisting of a few lines):
If your original batch script is as follows
cd C:\Users\ipython_user\Desktop
python filename.py
you can combine the lines together using the "&&" separator as follows in your
local_script.bat file:
https://stackoverflow.com/a/8055390/4752883:
cd C:\Users\ipython_user\Desktop && python filename.py
After this change, you can then run the script as pointed out here by
#JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883 with:
`plink root#MachineB -m local_script.bat`
Solution 2:
If your batch script is relatively complicated, it may be better to use a batch
script which encapsulates the plink command as well as follows as pointed out
here by #Martin https://stackoverflow.com/a/32196999/4752883:
rem Open tunnel in the background
start plink.exe -ssh [username]#[hostname] -L 3307:127.0.0.1:3306 -i "[SSH
key]" -N
rem Wait a second to let Plink establish the tunnel
timeout /t 1
rem Run the task using the tunnel
"C:\Program Files\R\R-3.2.1\bin\x64\R.exe" CMD BATCH qidash.R
rem Kill the tunnel
taskkill /im plink.exe
This bash script does ssh into a target remote machine, and run some command in the remote machine, do not forget to install expect before running it (on mac brew install expect )
#!/usr/bin/expect
set username "enterusenamehere"
set password "enterpasswordhere"
set hosts "enteripaddressofhosthere"
spawn ssh $username#$hosts
expect "$username#$hosts's password:"
send -- "$password\n"
expect "$"
send -- "somecommand on target remote machine here\n"
sleep 5
expect "$"
send -- "exit\n"
You can use runoverssh:
sudo apt install runoverssh
runoverssh -s localscript.sh user host1 host2 host3...
-s runs a local script remotely
Useful flags:
-g use a global password for all hosts (single password prompt)
-n use SSH instead of sshpass, useful for public-key authentication
If it's one script it's fine with the above solution.
I would set up Ansible to do the Job. It works in the same way (Ansible uses ssh to execute the scripts on the remote machine for both Unix or Windows).
It will be more structured and maintainable.
It is unclear if the local script uses locally set variables, functions, or aliases.
If it does this should work:
myscript.sh:
#!/bin/bash
myalias $myvar
myfunction $myvar
It uses $myvar, myfunction, and myalias. Let us assume they is set locally and not on the remote machine.
Make a bash function that contains the script:
eval "myfun() { `cat myscript.sh`; }"
Set variable, function, and alias:
myvar=works
alias myalias='echo This alias'
myfunction() { echo This function "$#"; }
And "export" myfun, myfunction, myvar, and myalias to server using env_parallel from GNU Parallel:
env_parallel -S server -N0 --nonall myfun ::: dummy
Extending answer from #cglotr. In order to write inline command use printf, it useful for simple command and it support multiline using char escaping '\n'
example :
printf "cd /to/path/your/remote/machine/log \n tail -n 100 Server.log" | ssh <user>#<host> 'bash -s'
See don't forget to add bash -s
There is another approach ,you can copy your script in your host with scp command then execute it easily .
First, copy the script over to Machine B using scp
[user#machineA]$ scp /path/to/script user#machineB:/home/user/path
Then, just run the script
[user#machineA]$ ssh user#machineB "/home/user/path/script"
This will work if you have given executable permission to the script.

inserting the Linux shell script file from windows to Linux box using powershell

so i am working on power shell and created the shell script file in C drive now i want to send that file using plink.exe by using power shell to Linux box.
Tried below commands
PS C:\> .\plink.exe -pw -i "R***t" root#192.168.1.12 ".\adduser.sh"
Unable to open connection:
PS C:\> .\plink.exe -i ssh "R***t" root#192.168.1.12 ".\adduser.sh"
PS C:\> .\plink.exe -i ssh "R***t" -P 22 root#192.168.1.12 ".\adduser.sh"
Unable to open connection:
PS C:\> .\plink.exe -i ssh "R***t" -P 22 root#192.168.1.12 ".\adduser.sh"
Unable to open connection:
basically how we can connect to Linux box usin g plink.exe through power shell
if we need any sshkey let me confirm and how can we generate the ssh
key for plink.exe and what are the options need to use for ssh key
so if any valuable suggestions appreciable and thanks in advance.....
plink is only a command-line interface for putty. Similar to the ssh command in unix/linux. You cannot upload/transfer files using plink.
You can use the pscp to do it.
Here's a reference to how you can create SSH keys to connect to your server without using a password.
https://the.earth.li/~sgtatham/putty/0.67/htmldoc/Chapter8.html#pubkey
plink is one tool in the entire suite of Simon Tatham's SSH package called PuTTY.
PuTTY provides SSH capabilities to WIndows users, and it comes with a bunch of compiled command line tools.
Plink is the equivalent of the SSH (secure (remote) shell) command on a linux machine.
Pscp is the equivalent of the SCP (Secure CoPy) command.
Psftp is the equivalent of SFTP (Secure File Transfer Protocol) which uses the same transfer methods as SCP but with an FTP like comman line interface.
PuTTY itself is a graphical tool that uses the same code as plink to create remote shells or commands over SSH or Telnet protocols (and many more), but it's probably a bit much to go into right now.
From the looks of it, it seems you are trying to get a shell script copied to your Linux server, so you should not be using the command to open a shell, but rather use the command to do a secure copy.
In short, use PSCP, not PLINK. (and maybe read the manual on it, so you get the arguments right)
TO insert the shell script file from windows machine to Linux box you need to download the "plink" file from internet and keep it in C:\drive and run the command like below
PS C:\> .\pscp.exe .\abc.sh root#1.2.3.4.:/root
after that you can use the plink to connect the linux box by using below command
PS C:\> .\plink.exe -pw "L****e" root#1.2.3.4 -P 22 "ls"
here "-pw" means password and "-P" means port number
I have briefly tried "Post-SSH" third-party module to Powershell, and it looks quite good. :)
Find-module Posh-SSH
Find-module Posh-SSH | Install-module
After that you can
$session = New-SSHSession -ComputerName "1.2.3.4" -Credential (Get-Credential)
Invoke-SSHCommand -Session $session -Command 'ls -l'
And finally close the session again
$session | Remove-SSHSession
http://www.thomasmaurer.ch/2016/04/using-ssh-with-powershell/

Execute a Linux application remotelly from PowerShell

I'm trying to execute a application console command (cslogin) on a Linux box from PowerShell. I used the SSH module from SSH.NET to access the Linux server. The following is a snapshot of my script, I'm able to establish the ssh session.
Import-Module SSH-Sessions
$user = "user"
$password = "pass"
$hostname = "192.168.1.X"
C:\plink.exe -ssh -l $username -pw $password $hostname "cslogin"
But once the cslogin command is executed the script hangs with the following message:
SEC054 A device has connected to, or disconnected from, a pseudo tty without
authenticating
At this point if I hit the enter key I am able to get the application prompt, which is what I want. I am trying to understand why does my script hangs and how do I get around this issue.
You only import the SSH-Sessions module, without actually using it. You then run PLink, that is not related to SSH.NET at all.
Pure SSH.NET solution is like:
Import-Module SSH-Sessions
New-SshSession -ComputerName "192.168.1.X" -Username "user" -Password "pass"
Invoke-SshCommand -InvokeOnAll "cslogin"
Other than that your PLink solution does the same. As it does not work, the SSH.NET solution above won't probably work either.
Your actual problem is that the application (cslogin) requires an interactive terminal (TTY). PLink by default does not allocate one. And I believe that SSH.NET does not either. With PLink, you can force TTY using -t switch:
$user = "user"
$password = "pass"
$hostname = "192.168.1.X"
plink.exe -ssh -l $username -pw $password $hostname -t "cslogin"
See Using the command-line connection tool Plink.
As far as I can see you're not actually using ssh.net here. Sure, you import the module but instead of using the New-SSHSession or Invoke-SSHCommand cmdlets you then run plink to connect and run cslogin. I confess I've not heard of that Linux command but bear in mind that plink expects to connect via SSH, execute a command and disconnect - so you won't get an interactive prompt.
You can either have plink run a script on the Linux server, or using the -m switch get plink to read a list of commands drone a file.
Alternatively you can setup a putty saved session then run plink to get interactive session but you might get some oddities in the powershell command window when it tries to interpret the output from plink.
for more info see this link

Best way to script remote SSH commands in Batch (Windows)

I am looking to script something in batch which will need to run remote ssh commands on Linux. I would want the output returned so I can either display it on the screen or log it.
I tried putty.exe -ssh user#host -pw password -m command_run but it doesn't return anything on my screen.
Anyone done this before?
The -m switch of PuTTY takes a path to a script file as an argument, not a command.
Reference: https://the.earth.li/~sgtatham/putty/latest/htmldoc/Chapter3.html#using-cmdline-m
So you have to save your command (command_run) to a plain text file (e.g. c:\path\command.txt) and pass that to PuTTY:
putty.exe -ssh user#host -pw password -m c:\path\command.txt
Though note that you should use Plink (a command-line connection tool from PuTTY suite). It's a console application, so you can redirect its output to a file (what you cannot do with PuTTY).
A command-line syntax is identical, an output redirection added:
plink.exe -ssh user#host -pw password -m c:\path\command.txt > output.txt
See Using the command-line connection tool Plink.
And with Plink, you can actually provide the command directly on its command-line:
plink.exe -ssh user#host -pw password command > output.txt
Similar questions:
Automating running command on Linux from Windows using PuTTY
Executing command in Plink from a batch file
You can also use Bash on Ubuntu on Windows directly. E.g.,
bash -c "ssh -t user#computer 'cd /; sudo my-command'"
Per Martin Prikryl's comment below:
The -t enables terminal emulation. Whether you need the terminal emulation for sudo depends on configuration (and by default you do no need it, while many distributions override the default). On the contrary, many other commands need terminal emulation.
As an alternative option you could install OpenSSH http://www.mls-software.com/opensshd.html and then simply ssh user#host -pw password -m command_run
Edit: After a response from user2687375 when installing, select client only. Once this is done you should be able to initiate SSH from command.
Then you can create an ssh batch script such as
ECHO OFF
CLS
:MENU
ECHO.
ECHO ........................
ECHO SSH servers
ECHO ........................
ECHO.
ECHO 1 - Web Server 1
ECHO 2 - Web Server 2
ECHO E - EXIT
ECHO.
SET /P M=Type 1 - 2 then press ENTER:
IF %M%==1 GOTO WEB1
IF %M%==2 GOTO WEB2
IF %M%==E GOTO EOF
REM ------------------------------
REM SSH Server details
REM ------------------------------
:WEB1
CLS
call ssh user#xxx.xxx.xxx.xxx
cmd /k
:WEB2
CLS
call ssh user#xxx.xxx.xxx.xxx
cmd /k

Send commands to Linux terminal with PuTTY

How can I send a command (not to open a file) with PuTTY that will run on a Linux terminal?
For example:
putty.exe 10.31.2.121 -l root -pw password | echo "Hi"
So that I will see the "Hi" on the Linux console?
Use plink.exe (from the developer of PuTTY).
And do something like the following
C:\putty\plink.exe user1#192.168.0.1 -pw P#55W0rD!
-m command.txt
I took this from Automate Cisco SSH connections with plink on Windows.

Resources