Modifying paramiko output before storing it in an array - python

I have a requirement to log into multiple devices,run multiple commands and store the output.I am currently achieving this using paramiko for remote SSH and then storing the results in an excel sheet using xlswriter. This is the code that I currently have :
import getpass
import paramiko
import xlsxwriter
username = raw_input('Enter username for device login:')
def enterPassword():
while True: # repeat forever
password = getpass.getpass('Enter corresponding password:')
password_again = getpass.getpass('Confirm password:')
if password != password_again:
print 'Password and confirmation do not match.Please try again!!'
else:
return password
password = enterPassword()
print "Running the tests..this might take some time.."
# Opens file in read mode
f1 = open('hostnames','r')
f2 = open('commandlist','r')
# Creates list based on f1
devices = f1.readlines()
commands = f2.readlines()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
data = []
for device in devices:
column = device.split()
data.append([column[0]])
print column[0]
for command in commands:
try:
conn=ssh.connect(column[1], username=username, password=password, timeout=4)
if conn is None:
stdin, stdout, stderr = ssh.exec_command(command)
data[-1].append(stdout.read())
ssh.close()
except paramiko.AuthenticationException:
output = "Authentication Failed"
data[-1].append(output)
break
except paramiko.SSHException:
output = "Issues with SSH service"
data[-1].append(output)
break
except socket.error, e:
output = "Connection Error"
data[-1].append(output)
break
data[-1] = tuple(data[-1])
f1.close()
f2.close()
book = xlsxwriter.Workbook('finalresults.xlsx')
sheet = book.add_worksheet('sheet1')
for row, data_in_row in enumerate(data):
for col, text in enumerate(data_in_row):
sheet.write(row + 1, col, text)
book.close()
This works perfectly fine on remote machines running bash and I get just the output of the commands that I run.However,on certain machines that don't run bash,I get the command run and extra prompts in the output as follows:
How do I strip the first line and the last two lines from the stdout.read() for each command within the loop.I have heard of using grep with subprocess but was looking for inbuilt python string operators
EDIT:
So I did a bit more reading,trolled a few sites and this is what I have :
data = []
offending = [">"]
for device in devices:
column = device.split()
data.append([column[0]])
print column[0]
for command in commands:
try:
conn=ssh.connect(column[1], username=username, password=password, timeout=4)
if conn is None:
stdin, stdout, stderr = ssh.exec_command(command)
for line in stdout.readline():
if not True in [item in line for item in offending]:
output = line
data[-1].append(output)
ssh.close()
However,now I have blank cells.I tried this on the command line interpreter and it worked fine.What could be wrong ??

Ok..so after a bit more research and trial and error,this snippet of code works:
data = []
for device in devices:
column = device.split()
data.append([column[0]])
print column[0]
for command in commands:
try:
conn=ssh.connect(column[1], username=username, password=password, timeout=4)
if conn is None:
stdin, stdout, stderr = ssh.exec_command(command)
output = '\n'.join(item for item in stdout.read().splitlines() if '>' not in item)
data[-1].append(output)
ssh.close()

Related

Python - Netmiko read from 2 columns

I have the following code that reads a CSV with a list of hostnames, and runs 2 commands.
I need to change this so that the CSV file it receives has 2 columns, one with the hostname, and another with the corresponding command to be inserted in that router.
Hostname
Comand
CPE_1111
sh ip int br
CPE_2222
sh run
etc
(...)
(...)
nodenum=1
f=open('routers.csv', 'r') #File with Hostnames
c=f.read()
file_as_list = c.splitlines()
with open('Output.txt','w') as f: #File with output
logf = open("error.csv", "a") #Logfile
loga = csv.writer(logf)
loga.writerow(["Hostname"])
for i in file_as_list :
print ("Node", nodenum, "...Checking IP Address...", i)
try:
Connection = netmiko.ConnectHandler(ip=i, device_type="cisco_ios" , username=raw_input("Enter your Username:"), password=getpass.getpass(), verbose=False)
except:
try:
print("Cannot connect via SSH. Trying Telnet")
Connection = netmiko.ConnectHandler(ip=i, device_type="cisco_ios_telnet" , username=raw_input("Enter your Username:"), password=getpass.getpass(), verbose=False)
except:
print("SSH and Telnet Failed")
print("")
now = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
loga.writerow([i])
nodenum = nodenum+1
continue
hostname = (Connection.send_command("show run | include hostname"))
cellular = (Connection.send_command("sh ip int brief"))
Connection.disconnect
(...)
Your answer lies with how the csv is read. You can use csv.DictReader() to read each row and convert it to a dictionary.
import csv
with open(file="routers.csv", mode="rt") as f:
next(f)
lst = csv.DictReader(f=f, fieldnames=["ip", "cmd"])
ips_cmds = list(lst)
for ip_cmd in ips_cmds:
print("Hostname:", ip_cmd["ip"])
print("Command:", ip_cmd["cmd"], end="\n\n")
# Hostname: CPE_1111
# Command: show ip interface brief
# Hostname: CPE_2222
# Command: show running-config
Then in the for loop where you connect to each router, you can select the value you need from the keys specified in fieldnames.
conn = ConnectHandler(
device_type="cisco_ios",
ip=ip_cmd["ip"],
username=input("Username: "),
password=getpass(prompt="Password: "),
secret=getpass(prompt="Enable Secret: "),
fast_cli=False,
)
hostname = conn.send_command(command_string=ip_cmd["cmd"])
Don't forget to add the parentheses for disconnect() function to be executed.
conn.disconnect()

AttributeError: 'NoneType' object has no attribute 'exec_command', when converting code lines into a function, in python

This question is related to this one: How to use sockets to send user and password to a devboard using ssh
How can I put CODE A into a function? Explain me what am I doing wrong.
CODE A
import paramiko
import os
#Server's data
IP = '172.16.2.82'
PORT = 22
USER = 'mendel'
PASSWORD = 'mendel'
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname = IP, port=PORT, username = USER, password = PASSWORD)
stdin, stdout, stderr = ssh.exec_command('cd coral/tflite/python/examples/classification/Auto_benchmark\n python3 auto_benchmark.py')
output = stdout.readlines()
type(output)
print('\n'.join(output))
ssh.close()
This is my attempt:
def initialize_ssh():
n = 0
while n <= 10:
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname = IP, port=PORT, username = USER, password = PASSWORD)
return
except paramiko.AuthenticationException:
print("Authentication failed, please verify your credentials: %s")
except paramiko.SSHException as sshException:
print("Unable to establish SSH connection: %s" % sshException)
n += 1
continue
raise Exception
def main():
ssh = initialize_ssh()
stdin, stdout, stderr = ssh.exec_command('cd coral/tflite/python/examples/classification/Auto_benchmark\n python3 auto_benchmark.py')
output = stdout.readlines()
type(output)
print('\n'.join(output))
ssh.close()
if __name__ == '__main__':
main()
EDIT AFTER SUGGESTIONS FROM COMMENTS
def main():
ssh = initialize_ssh()
stdin, stdout, stderr = ssh.exec_command('ls')
output = stdout.readlines()
type(output)
print('\n'.join(output))
ssh.close()
return ssh <------------------- HERE IS THE CHANGE
Your first change should be to return ssh:
def initialize_ssh():
n = 0
while n <= 10:
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname = IP, port=PORT, username = USER, password = PASSWORD)
return ssh # the return is here
except paramiko.AuthenticationException:
print("Authentication failed, please verify your credentials: %s")
except paramiko.SSHException as sshException:
print("Unable to establish SSH connection: %s" % sshException)
n += 1
continue
raise Exception

Login to multiple servers using one of the two passwords used for authentication using Python

I am new to Python.
I am using Paramiko module to login to the Linux servers. However I have 2 different passwords for authentication and I want the server to be logged in using either of them. In case both fails, I am raising the exception for it.
I am facing problem when I have to use the second password. Here is sample for the same.
server.txt is having the list of servers
file1 = 'D:\Linux\server.txt'
with open(file1) as f:
switch_ip = f.readlines()
switch_ip = [x.strip() for x in switch_ip]
username = "user1"
password1 = "abcd2"
password2 = "efcdrf2"
def simple_out(cmd):
try:
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
x=[]
ssh.connect(IP,port =22,username = username, password = password1 or password2)
pass
time.sleep(2)
stdin, stdout, stderr = ssh.exec_command(cmd)
line1 = stdout.readline() #read line by line
while line1:
split_words = line1.split() #List
# split_words.insert(0,IP)
print split_words
str1 = ' '.join(split_words) #String
x.append(str1)
line1=stdout.readline()
return [x]
except (paramiko.BadHostKeyException, paramiko.AuthenticationException, paramiko.SSHException, socket.error) as e:
time.sleep(2)
buf = StringIO.StringIO(e)
line3 = buf.read()
y=[line3]
return [y]
for IP in switch_ip:
output = simple_out("df -h") # will call function and execute command
out1 = output[0] #t
for items in out1:
book = xlrd.open_workbook('D:\\Linux\\xlwt example.xls')
sheet2 = book.sheet_by_index(0)
row_count = sheet2.nrows
column_count = 1
sheet1.write(row_count, 0, IP)
sheet1.write(row_count, column_count, items)
wb.save('D:\\Linux\\xlwt example.xls')
time.sleep(2)
I want to login to the servers using either of the 2 passwords
you can use try catch block for each password and continue in your program see below example:
try:
ssh.connect(IP,port =22,username = username, password = password1)
except paramiko.AuthenticationException as e: #catch other exceptions as well
ssh.connect(IP,port =22,username = username, password = password2)

\n is messing my script up

I have a script that will successfully run if I assign a list inside the main function, but I need to run through this on 100+ devices. I've spent some time researching and I think the best way to do this would be to store the variables in a text file and access it that way. (Of course, if someone knows a better way, I'm all for it!)
My issue now is that when I try to convert the existing code to account for the new text file full of variables, I'm getting:
TypeError: getaddrinfo() argument 1 must be string or None"
I'm pretty sure I'm seeing those because of the \n line break because it will fail up until the last line, and that one works.
So far, I've tried the line.split & save the txt file as a .csv and change the delimiter to \n but neither are working quite the way I expected.
Below is the script that works:
import sys, os, string, threading
import getpass
import paramiko
import time
cmd = "sh vl bri"
lanid = 'admin'
pwd = 'password'
outlock = threading.Lock()
def workon(host):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=lanid, password=pwd)
stdin, stdout, stderr = ssh.exec_command(cmd)
#print stdout.read()
stdin.flush()
with open("output-" + host + ".txt", 'w+') as f:
f.seek(0)
f.write(stdout.read())
with outlock:
print stdout.readlines()
#f.write(stdout)
def main():
hosts = ['sw1', 'sw2', 'sw3'] # etc
threads = []
for h in hosts:
t = threading.Thread(target=workon, args=(h,))
t.start()
threads.append(t)
for t in threads:
t.join()
main()
EDIT 1
import sys, os, string, threading
import getpass
import paramiko
import time
cmd = "sh vl bri"
#lanid = raw_input("Enter your uname: ")
lanid = 'admin'
pwd = 'password'
outlock = threading.Lock()
def workon(stripped_row):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(stripped_row, username=lanid, password=pwd)
stdin, stdout, stderr = ssh.exec_command(cmd)
#print stdout.read()
stdin.flush()
with open("output-" + stripped_row + ".txt", 'w+') as f:
f.seek(0)
f.write(stdout.read())
with outlock:
print stdout.readlines()
#f.write(stdout)
def main():
my_file = open('10host.txt')
threads = []
for h in my_file:
striped_row = h.strip()
t = threading.Thread(target=workon, args=(h,))
t.start()
threads.append(t)
for t in threads:
t.join()
main()
The problem lies here:
for h in my_file:
striped_row = h.strip()
t = threading.Thread(target=workon, args=(h,))
You're stripping the current line, but then pass the unstripped line to your worker function. Try to pass the striped_row as argument instead of h.

While loop using text file, only uses last line - Python 2.x

I've been coding a small SSH brute forcer, to understand the paramiko module. However while going through the text file to see each password it is only testing out the last password in the text file. Am I using the correct loop? How would I use the for loop in this situation then?
import paramiko
UserName = 'msfadmin'
pass_file = 'pass.txt'
ip_file = 'ip.txt'
port = 22
Found = 0
pwd = open(pass_file, "r")
ips = open(ip_file, "r")
def attempt():
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for line in ips.readlines():
ip = line.strip()
for line2 in pwd.readlines():
Passwords = line2.strip()
while Found != 5:
global UserName
global port
try:
ssh.connect(ip, port, username=UserName, password=Passwords)
except paramiko.AuthenticationException:
print '[-] %s:%s fail!' % (UserName, Passwords)
else:
print '[!] %s:%s is CORRECT!' % (UserName, Passwords)
for line in ips.readlines():
ip = line.strip()
for line2 in pwd.readlines():
Passwords = line2.strip()
You are getting each and every line and replace the previous value in ip and passwords with the currently read value. Instead, if the number of ips and passwords are relatively smaller, you can do
count = 0
for ip in ips:
for pwd in open(pass_file, "r"):
try:
ssh.connect(ip, port, username=UserName, password=pwd)
except paramiko.AuthenticationException:
print '[-] %s:%s fail!' % (UserName, pwd)
else:
print '[!] %s:%s is CORRECT for IP %s!' % (UserName, pwd, ip)
count += 1
if count == 5:
return
Your two for loops simply iterate through each object and update the ip and Password variables each time, so that when they have finished the variables refer to the last values from the loop.
However it's not at all clear what you are trying to do with those variables, so I can't tell you how to fix it. Did you want to run the rest of the script once for each iteration? Or did you want to create a list of all the elements, then iterate through that?

Categories