Python ssh script loop problems - python

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()

Related

Enter key works manually but not when sent via paramiko invoke_shell.sendall

I am looking for a way to login via SSH to a Cisco UCS server and execute few commands.
I am able to login and execute several commands and get the output. But the one command that requires y and Enter key doesn't seem to work.
If I try the same via terminal manually, it works. Looks like Enter key is not being executed on the server regardless of using \n, \r or \r\n.
ssh = paramiko.client.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=username, password=password)
ucs = ssh.invoke_shell()
ucs.sendall('scope chassis\r\n')
time.sleep(2)
ucs.sendall('power on\r\n')
time.sleep(2)
ucs.sendall("y\r\n")
time.sleep(10)
ucs.sendall('show\r\n')
time.sleep(10)
s = ucs.recv(4096)
with open("Output.txt", "ab") as text_file:
text_file.write(s)
with open("temp2", "wb") as text_file:
text_file.write(s)
ssh.close()
hostname# scope chassis
hostname /chassis #
hostname /chassis # power on
This operation will change the server's power state.
Do you want to continue?[y|N]y
hostname /chassis #
hostname /chassis # show
Power Serial Number Product Name PID UUID
----- ------------- ------------- ------------- ------------------------------------
off xxxxxxxxxxx UCS C240 M3S UCSC-C240-M3S xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I would be looking at this command:
ucs.sendall('power on\r\n')
It is possible that because you are using both \r and \n that the console is interpreting the \r to accept the power on command and the \n to immediately cancel it. So before you get the chance to input Y, the command has already been cancelled by the preceding \n.

Read command output in Paramiko without prompts and other shell output

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.

How to connect Paramiko stdin to console? [duplicate]

I'm trying to run an interactive command through paramiko. The cmd execution tries to prompt for a password but I do not know how to supply the password through paramiko's exec_command and the execution hangs. Is there a way to send values to the terminal if a cmd execution expects input interactively?
ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")
Does anyone know how this can addressed? Thank you.
The full paramiko distribution ships with a lot of good demos.
In the demos subdirectory, demo.py and interactive.py have full interactive TTY examples which would probably be overkill for your situation.
In your example above ssh_stdin acts like a standard Python file object, so ssh_stdin.write should work so long as the channel is still open.
I've never needed to write to stdin, but the docs suggest that a channel is closed as soon as a command exits, so using the standard stdin.write method to send a password up probably won't work. There are lower level paramiko commands on the channel itself that give you more control - see how the SSHClient.exec_command method is implemented for all the gory details.
I had the same problem trying to make an interactive ssh session using ssh, a fork of Paramiko.
I dug around and found this article:
Updated link (last version before the link generated a 404): http://web.archive.org/web/20170912043432/http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/
To continue your example you could do
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")
ssh_stdin.write('password\n')
ssh_stdin.flush()
output = ssh_stdout.read()
The article goes more in depth, describing a fully interactive shell around exec_command. I found this a lot easier to use than the examples in the source.
Original link: http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/
You need Pexpect to get the best of both worlds (expect and ssh wrappers).
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(server_IP,22,username, password)
stdin, stdout, stderr = ssh.exec_command('/Users/lteue/Downloads/uecontrol-CXC_173_6456-R32A01/uecontrol.sh -host localhost ')
alldata = ""
while not stdout.channel.exit_status_ready():
solo_line = ""
# Print stdout data when available
if stdout.channel.recv_ready():
# Retrieve the first 1024 bytes
solo_line = stdout.channel.recv(1024)
alldata += solo_line
if(cmp(solo_line,'uec> ') ==0 ): #Change Conditionals to your code here
if num_of_input == 0 :
data_buffer = ""
for cmd in commandList :
#print cmd
stdin.channel.send(cmd) # send input commmand 1
num_of_input += 1
if num_of_input == 1 :
stdin.channel.send('q \n') # send input commmand 2 , in my code is exit the interactive session, the connect will close.
num_of_input += 1
print alldata
ssh.close()
Why the stdout.read() will hang if use dierectly without checking stdout.channel.recv_ready(): in while stdout.channel.exit_status_ready():
For my case ,after run command on remote server , the session is waiting for user input , after input 'q' ,it will close the connection .
But before inputting 'q' , the stdout.read() will waiting for EOF,seems this methord does not works if buffer is larger .
I tried stdout.read(1) in while , it works
I tried stdout.readline() in while , it works also.
stdin, stdout, stderr = ssh.exec_command('/Users/lteue/Downloads/uecontrol')
stdout.read() will hang
I'm not familiar with paramiko, but this may work:
ssh_stdin.write('input value')
ssh_stdin.flush()
For information on stdin:
http://docs.python.org/library/sys.html?highlight=stdin#sys.stdin
Take a look at example and do in similar way
(sorce from http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/):
ssh.connect('127.0.0.1', username='jesse',
password='lol')
stdin, stdout, stderr = ssh.exec_command(
"sudo dmesg")
stdin.write('lol\n')
stdin.flush()
data = stdout.read.splitlines()
for line in data:
if line.split(':')[0] == 'AirPort':
print line
You can use this method to send whatever confirmation message you want like "OK" or the password. This is my solution with an example:
def SpecialConfirmation(command, message, reply):
net_connect.config_mode() # To enter config mode
net_connect.remote_conn.sendall(str(command)+'\n' )
time.sleep(3)
output = net_connect.remote_conn.recv(65535).decode('utf-8')
ReplyAppend=''
if str(message) in output:
for i in range(0,(len(reply))):
ReplyAppend+=str(reply[i])+'\n'
net_connect.remote_conn.sendall(ReplyAppend)
output = net_connect.remote_conn.recv(65535).decode('utf-8')
print (output)
return output
CryptoPkiEnroll=['','','no','no','yes']
output=SpecialConfirmation ('crypto pki enroll TCA','Password' , CryptoPkiEnroll )
print (output)

Python ssh command to change user

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)

I want to execute multiple commands through a single channel of ssh, implemented using paramiko library.

I need to execute multiple commands(in a specific sequential order) in the same established channel of a switch in a storage network.
But every time I use exec_command(command) a new channel is opened and the command is sent to the switch.
Since the commands have to be sequentially executed, nothing is going through.
So, my doubt is, how to send multiple sequential commands through a single ssh channel, implemented using paramiko library.
To execute multiple command in single channel of ssh. you need to invoke interactive shell by
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname, port, username, password)
channel = ssh.invoke_shell()
Then send command to terminal by
channel.send(command)
and receive command output by
channel.recv(9999)
print the output by
channel.recv(9999).decode()
If your goal is to send multiple commands in the same host and receive the outcome of those commands, I've written a script that works well (in this case to ping several elements):
# -*- coding: utf-8 -*-
"""
Created on Thu May 5 10:56:10 2016
#author: Me
"""
import paramiko as pk
class cii(Exception):
pass
num = int(input('number : '))
while True :
try:
if len(str(num)) != 5 :
raise cii
except cii:
print ('error message')
break
else:
with open (r'path.txt') as search :
try:
for line in search :
line = line.rstrip()
line1 = line.split(",")
IP = line1[2]
line2 = line1[2].split('.')
line3 = (int(line2[3])+1)
del line2[3]
line2.append(str(line3))
CA = str(".".join(line2))
Machine = line1[1]
Command = 'ping -n 1'
if str(num) in line and yy == 'xx' :
ssh = pk.SSHClient()
ssh.set_missing_host_key_policy(
pk.AutoAddPolicy())
ssh.connect('{}'.format(IP), port=xxxx, username='xxxxxx',
password='xxxx')
stdin, stdout, stderr = \
ssh.exec_command('ping -n 1 xxx.xxx.xxx.xxx\n')
print('Ping xx: \n', stdout.readlines())
ssh = pk.SSHClient()
ssh.set_missing_host_key_policy(
pk.AutoAddPolicy())
ssh.connect('{}'.format(IP), port=xxxx, username='xxxxxx',
password='xxxx')
stdin, stdout, stderr = \
ssh.exec_command('ping -n 1 xxx.xxx.xxx.xxx\n')
print('Ping xx: \n', stdout.readlines())
ssh = pk.SSHClient()
ssh.set_missing_host_key_policy(
pk.AutoAddPolicy())
ssh.connect('{}'.format(IP), port=xxxx, username='xxxxxx',
password='xxxx')
stdin, stdout, stderr = \
ssh.exec_command('ping -n 1 xxx.xxx.xxx.xxx\n')
print('Ping xx: \n', stdout.readlines())
ssh = pk.SSHClient()
ssh.set_missing_host_key_policy(
pk.AutoAddPolicy())
ssh.connect('{}'.format(xx), port=xxxx, username='xxxxxxx',
password='xxxxxxx')
stdin, stdout, stderr = \
ssh.exec_command('{} {}'.format(Command, CA).encode('ascii') + b"\n")
print('Ping CA: \n', stdout.readlines())
break
except TimeoutError:
print ('error message')
break
input ('\n keep windows open and then Enter to exit \n')
You can send multiple commands by opening a new connection each time. Hope it helps.

Categories