I need to run a python script that will ssh to a remote host. The first command to run on this remote host is "sudo su". I have the password for it. Then I need to cd to a directory and copy a file to my local box. I tried in two ways. Both of them don't work.
script #1:
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostName,username='e0258595',password='<password>')
stdin,stdout,stderr = ssh.exec_command("sudo su; whoami")
stdin.write('password\n')
stdin.flush()
data = stdout.readlines()
for line in data:
print line
The output is still e0258595.
Script #2:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostName, username="e0258595", password="<password>")
transport = ssh.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
#for testing purposes we want to force sudo to always to ask for password. because of that we use "-k" key
session.exec_command("sudo su; whoami")
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
#you have to check if you really need to send password here
stdin.write("<password>"+'\n')
stdin.flush()
data = stdout.readlines()
for line in data:
print line
This one just hang.
What is the problem?
Have you tried using get_pty=True?
stdin,stdout,stderr = ssh.exec_command("sudo su; whoami", get_pty=True)
Related
I'm trying to send an output of a specific command to a txt file,
file = 'output_from_the_server.txt'
def connect(host):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname=host, port=port, username=username, password=password, look_for_keys=False, allow_agent=False)
ssh = client.invoke_shell()
return ssh
def test(server_host):
print(server_host)
IP = server_view(server_host)
print(IP)
ssh = connect(IP)
time.sleep(2)
ssh.send('clear -x && [command]\n')
time.sleep(3)
resp = ssh.recv(655353)
output = resp.decode('ascii').split(',')
output = ''.join(output)
ssh.close()
with open(file, 'w') as f:
for i in output:
f.write(i)
f.close()
The file include all of the outputs before the command, even i tried to use clear screen.
You are starting a shell, so naturally you get all the output you would get in the shell, including all prompts and banners.
Do not use shell to automate command execution, use the "exec" SSH channel.
stdin, stdout, stderr = client.exec_command(command)
stdout.channel.set_combine_stderr(True)
output = stdout.readlines()
See Paramiko: read from standard output of remotely executed command.
Related question:
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?
Obligatory warning: Do not use AutoAddPolicy on its own – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
Here's an example of executing a command through a paramiko.
Sending the output to a file should then be easy.
def ssh_command(ip, user, command):
key = paramiko.RSAKey.from_private_key_file(os.getenv('HOME') + '/.ssh/paramiko')
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ip, username=user, pkey=key)
ssh_session = client.get_transport().open_session()
if ssh_session.active:
ssh_session.exec_command(command)
out = []
r = ssh_session.recv(1024).decode('utf-8')
while r:
out.append(r)
r = ssh_session.recv(1024).decode('utf-8')
return ''.join(out)
return ''
res = ssh_command('127.0.0.1', 'user', 'cd / ; ls */ | xargs ls')
for outputin str(res).split('\\n'):
print(output)
Don't forget to generate a key with ssh-keygen.
Could you help me with following.
I need to login as user then sudo su - then run command ex. parted -l using Paramiko exec_command
when I run following code it hangs. Please let me know how I can check before gets to hanged.
with SSHClient() as client:
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('172.20.xxx.xx', port=22, username='xxx', password='xxxxxxx',timeout=15.0)
transport = client.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
session.exec_command('sudo su -')
time.sleep(5)
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
stderr = session.makefile_stderr('rb', -1)
stdin.write('xxxxxxx' + '\n')
stdin.flush()
session.exec_command('parted -l')
time.sleep(5)
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
stderr = session.makefile_stderr('rb', -1)
stdin.flush()
for line in stdout.read().splitlines():
print 'LINE: %s' % (line)
Do you want to check result of the individual parted command? If you want to check results of individual commands, do not run shell (su in this case). Run the command only:
sudo su -c "parted -l"
See also Executing command using "su -l" in SSH using Python
Then you can use recv_exit_status():
How can you get the SSH return code using Paramiko?
If you want to keep your current approach for whatever reason, see:
Execute multiple dependent commands individually with Paramiko and find out when each command finishes
Combining interactive shell and recv_exit_status method using Paramiko
I am trying to write a Python 3 script to pragmatically ssh into a Linux server and change the password. I have put a script together using the Paramiko module.
I am running into issues when trying to run multiple shell commands. My script attempts to execute the commands but Paramiko times out after one shell command.
This is the script I am currently working on. Any insight would be greatly appreciated.
import paramiko
def change_pw():
hostname = "IP" #IP Address of Linux Server
username = "root" #username
password = "oldpw!" #password for Linux Server
#NOTE - This variable is suppose to define 3 shell commands. I do not believe the script is sending these commands as listed because the password does not update.
commands = [
"passwd",
"newpw!",
"newpw!"
]
#NOTE - Attempted to utilize '\n' to execute multiple commands and failed
# commands = [
# "passwd \n newpw! \n newpw!"
# ]
# initialize the SSH clientp0-
client = paramiko.SSHClient()
# add to known hosts
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
client.connect(hostname=hostname, username=username, password=password)
except:
print("[!] Cannot connect to the SSH Server")
exit()
# execute the commands
for command in commands:
print("="*50, command, "="*50)
stdin, stdout, stderr = client.exec_command(command)
print(stdout.read().decode())
err = stderr.read().decode()
if err:
print(err)
change_pw()
You do not have three commands. You have one command, the passwd, which takes two lines of input.
These two questions show how to provide an input to commands using Paramiko:
Pass input/variables to command/script over SSH using Python Paramiko
Executing command using "su -l" in SSH using Python
So specifically for passwd, you need to use:
stdin, stdout, stderr = client.exec_command('passwd')
# answer the new password prompts
stdin.write('newpw\n')
stdin.write('newpw\n')
stdin.flush()
# wait for the command to complete a print the output
stdout.channel.set_combine_stderr(True)
print(stdout.read().decode())
For the purpose of the Channel.set_combine_stderr, see Paramiko ssh die/hang with big output.
Obligatory warning: Do not use AutoAddPolicy – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
The issue is that I was trying to utilize 3 input commands to change the password for root. I only needed to call the passwd command and then pass two input variables for "Enter new PW" and "Confirm new PW"
import paramiko
import time
hostname = 'IP'
username = 'root'
password = 'oldpw'
commands = ['passwd']
# initialize the SSH clientp
client = paramiko.SSHClient()
# add to known hosts
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
client.connect(hostname=hostname, username=username, password=password)
except:
print("[!] Cannot connect to the SSH Server")
exit()
# execute the commands
for command in commands:
print("="*50, 'PW change executed', "="*50)
stdin, stdout, stderr = client.exec_command(command)
stdin.write('newpw' '\n' 'newpw' '\n') #input varuables for "Enter new PW" and "re-enter new PW"
stdin.flush()
print(stdout.read().decode())
err = stderr.read().decode()
if err:
print(err)
I've got a python script I'm trying to install a rpm package on but when I send the command to install it doesn't wait for the command to finish before restarting the service. I've read a lot of forums about using recv_exit_status() but I don't think I'm using it right.
This is what I have:
#!/usr/bin/python
import paramiko, os
from getpass import getpass
# Setting Variables
Hosts = [ '192.168.1.1', '192.168.1.2'] #IPs changed for posting
username = 'root'
print 'Enter root password on remote computer:'
password = getpass()
port = 22
File = 'Nessus-6.11.2-es7.x86_64.rpm'
for host in Hosts:
print 'Finished copying files. Now executing on remote computer'
#Setting up SSH session to run commands
remote_client = paramiko.SSHClient()
remote_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
remote_client.connect(host, username=username, password=password)
InstallNessus = 'rpm -U --percent %s'%File
stdin, stdout, stderr = remote_client.exec_command(InstallNessus)
stdout.channel.recv_exit_status()
lines = stdout.readlines()
for line in lines:
print line
stdin, stdout, stderr = remote_client.exec_command('systemctl restart nessusd.service')
remote_client.close()
I've tried using Fabric but I seem to be messing up my syntax somewhere.
add get_pty=True This will wait until command execution completed. stdin,stdout,stderr = self.ssh.exec_command(command,get_pty=True)
It's channel.recv_exit_status(), not stdout.channel.recv_exit_status().
However, since you are trying to run the same command over many servers, something like parallel-ssh is a better fit and much faster than paramiko, both sequentially and in parallel.
Code to do it is also much simpler, just:
from pssh.pssh2_client import ParallelSSHClient
hosts = ['192.168.1.1', '192.168.1.2']
_file = 'Nessus-6.11.2-es7.x86_64.rpm'
cmd = 'rpm -U --percent %s' % _file
client = ParallelSSHClient(hosts, user='<user>', password='<password>')
output = client.run_command(cmd)
for host, host_output in output.items():
for line in host_output.stdout:
print "Host %s: %s" % (host, line)
print "Host %s exit code %s" % (host, host_output.exit_code)
restart_out = client.run_command('systemctl restart nessusd.service')
# Just wait for completion
client.join(restart_out)
See documentation for further information.
I'm no programmer, but I try modify the following script.
http://www.networking-forum.com/wiki/Python_SSH_Script
I would like to make the script a bit more efficient.
At the moment the for loop makes the script do a new login for each command.
I would like the script do one login for each device and run all commands with one output for each device.
Here is the for loop:
# This function loops through devices. No real need for a function here, just doing it.
def connect_to(x):
for device in x:
# This strips \n from end of each device (line) in the devices list
device = device.rstrip()
# This opens an SSH session and loops for every command in the file
for command in commands:
# This strips \n from end of each command (line) in the commands list
command = command.rstrip()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(device, username=username, password=password)
stdin, stdout, stderr = ssh.exec_command(command)
output = open(device + ".out", "a")
output.write("\n\nCommand Issued: "+command+"\n")
output.writelines(stdout)
output.write("\n")
print "Your file has been updated, it is ", device+".out"
ssh.close()
connect_to(devices)
f1.close()
f2.close()
# END
After looking at the correct indentation found on your source check out the modifications below. This was inspired from this SO answer.
NOTE I do not have a target to ssh into and test these modifications.
def connect_to(x):
for device in x:
# Connect to the target
device = device.rstrip()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(device, username=username, password=password)
# Open up a stream for the conncction
channel = ssh.invoke_shell()
ssh_stdin = channel.makefile('wb')
ssh_stdout = channel.makefile('rb')
output = open(device + ".out", "a")
# Send all of the commands to the open session
for command in commands:
# This strips \n from end of each command (line) in the commands list
command = command.rstrip()
# send the command
ssh_stdin.write(command)
# Update the local log file
output.write("\n\nCommand Issued: "+command+"\n")
output.writelines(ssh_stdout.read())
output.write("\n")
print "Your file has been updated, it is ", device+".out"
# Close the connection after all of the commands have been issued
output.close()
ssh_stdin.close()
ssh_stdout.close()
ssh.close()