Esse script possibilita a execução de comandos remotamente utilizando o protocolo SSH. Os comandos podem ser executados individualmente ou em lote para um ou mais servidores.
O script foi desenvolvido em Python para Windows e utilizando paramiko e pycrypto para instalar o SSH nesse sistema. As versões citadas no READ-ME abaixo certamente estão desatualizadas. Para executar a partir de uma máquina Linux não deve ter qualquer problema.
READ.ME
bssh - ver. 0.3
Bulk SSH (bssh) is a python script written to provide remote command
submission to one or more servers/hosts using ssh protocol. Written to run
on Win32 environment, should run on Linux with minor or no modification.
VERSION HISTORY:
0.1: Simple command execution
0.2: Support to input response to programs running on remote host.
0.3: Added username and password parameters.
INSTALATION:
Download and run the following installers:
http://www.python.org/ftp/python/2.7.1/python-2.7.1.msi
http://bialix.com/python/paramiko-1.7.3-ctypes.win32.exe
http://www.serenethinking.com/bitlift/tl_files/pycrypto-2.3.win32-py2.7.msi
USAGE:
bssh <options>
OPTIONS:
-h, --help
Show this help.
-d, --debug
Show debug messages.
-c, --command=<command>
Single command to be executed on remote server.
-f, --commandfile=<command file name>
Name of the file containing all commands that will run on remote
server. (See below for details)
-s, --server=<server name>
Single target server name or IP address.
-l, --serverlist=<server list file name>
Name of the file containing all target servers names or IP address,
one per line.
-o, --output=<file name>
Sends output text to a file.
-u, --username=<user id>
User id to ssh sign-on.
-p, --password=<password>
User password to ssh sign-on.
COMMAND FILE:
Text file containing one command per line to be executed on the remote
host/server. Each command is preceded of a meta command to be interpreted
by bssh script as follows.
Meta commands:
$C <command>
Executes a command on remote host and catches it's stdout
$R <command>
Run a program and feeds to it's prompts with "input text" ($I)
provided right below.
$I <input text>
Text to be provided to programa executed with "run" ($R) command.
For consecutive responses, use $I for each program prompt.
# <comment>
The trailing text will not be executed and will be considered as
a comment.
Additionaly to meta commands there are some meta data that can be used
in a command line.
Meta data:
$user$
Replaced by username provided as credential to SSH login.
$pass$
Replaced by password provided as credential to SSH authentication.
CÓDIGO
#
# bssh - Bulk SSH
# Description: Submit a single command or a command sequence to remote
# host(s) using SSH protocol.
# Author.....: Megumi K. Jr.
# Date.......: Sep, 12 2011
# Version history:
# 0.3: Added user and password parameter option
#
scriptname = "bssh" # Script Name
scriptver = "0.3" # Version
#
import os, re, sys
import string
import getpass
import getopt
import time
import paramiko
from types import * # http://docs.python.org/library/types.html#module-types
def main():
global username
global password
global debug
command = None
cmdfile = None
server = None
serverlist = None
username = None
password = None
debug = False
# Check if options were informed
try:
opts, args = getopt.getopt(sys.argv[1:], "hdc:f:s:l:o:u:p:", \
["help", "debug", "command=", "commandfile=", "server=", "serverlist=", "output=", "username=", "password="])
except getopt.GetoptError, err:
# print help information and exit:
print str(err)
print
Usage()
sys.exit(2)
# Get all options
for o, a in opts:
if o in ("-h", "--help"):
Usage()
sys.exit()
elif o in ("-d", "--debug"):
debug = True
elif o in ("-c", "--command"):
command = a
elif o in ("-f", "--commandfile"):
cmdfile = a
elif o in ("-s", "--server"):
server = a
elif o in ("-l", "--serverlist"):
serverlist = a
elif o in ("-o", "--output"):
sys.stdout = Logger(a)
elif o in ("-u", "--username"):
username = a
elif o in ("-p", "--password"):
password = a
else:
Usage()
sys.exit(2)
# Check if is only one command to be executed
if command != None:
# only one command to be run
cmd = command # var "cmd" will have the command
else:
if cmdfile != None:
try:
# var "cmd" will have file handler
cmd = open(cmdfile)
except IOError as e:
print("{0}".format(e))
sys.exit(2)
else:
Usage()
sys.exit(2)
# Check if is only one server
if server != None:
# will run commands only on one server
srv = server # var "srv" will have server name
else:
if serverlist != None:
# Open server list file
try:
# var "srv" will have file handler
srv = open(serverlist)
except IOError as e:
print("{0}".format(e))
sys.exit(2)
else:
Usage()
sys.exit(2)
# Get user credentials
print
print "%s - ver. %s" % (scriptname, scriptver)
if username == None:
print "Logon credentials"
username = raw_input('Username: ')
password = getpass.getpass("Password: ")
ProcServer(srv, cmd)
return
# endDef
def Usage():
try:
helpfile = sys.path[0] + "\\READ.ME"
help = open(helpfile)
except IOError as e:
print 'Error reading "%s" file.' % helpfile
print("{0}".format(e))
sys.exit(2)
help.close()
cmd = 'more "%s"' % helpfile
os.system(cmd)
print
sys.exit(0)
# endDef
def ProcServer(srv, cmd):
# Process a server or servers list
if type(srv) == StringType: # If srv is StringType, contains server name
ProcCommand(srv, cmd) # proc single server
else:
for servername in srv.read().splitlines(): # loop into server file
if servername.strip() == "": # Skip empty lines
continue
elif servername.strip()[0] == "#": # Skip comments
continue
else:
ProcCommand(servername, cmd)
#endDef
def ProcCommand(srv, cmd):
print
print "Host: %s" % srv
print "-----------------------------------------------------------------------"
ssh = OpenConnection(srv)
if type(cmd) == StringType: # If cmd is StringType, contains single command
ExecCmd(ssh, cmd)
else:
cmd.seek(0) # Point to file beginning
ParseCmdFile(ssh, cmd)
#endDef
def ParseCmdFile(ssh, cmd):
cmdList = []
for command in cmd.read().splitlines():
# Ignore empty lines or comments
if command.strip() == "": # Skip empty lines
continue
elif command.strip()[0] == "#": # Skip comments
continue
command = NormalizeString(command)
if command.strip()[:2].upper() == "$C":
if len(cmdList) > 0: # If there's a pending program
ExecCmd(ssh, cmdList) # execution, do it before
cmdList = [] # the next command.
command = command[2:].strip()
ExecCmd(ssh, command)
elif command.strip()[:2].upper() == "$R"\
or command.strip()[:2].upper() == "$I":
cmdList.append(command[2:].strip())
continue
if len(cmdList) > 0: # If there's a pending program
ExecCmd(ssh, cmdList) # execution, do it before exit
return
# endDef
def OpenConnection(server):
if debug: # Turn on debug messages
paramiko.common.logging.basicConfig(level=paramiko.common.DEBUG)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(server, username=username, password=password)
except Exception, e:
print("({0})".format(e))
sys.exit(2)
return ssh
# endDef
def ExecCmd(ssh, command):
if type(command) == ListType: # If it is a list of commands
cmd = command[0] # get 1st cmd.
else:
cmd = command
print "$> %s" % (cmd)
stdin, stdout, stderr = ssh.exec_command(cmd)
if type(command) == ListType: # If it is a list of commands
for cmd in command[1:]: # continue sending next on
stdin.write(cmd+"\n") # the list
stdin.flush()
stdin.close()
for line in stdout.read().splitlines():
print line
print
return stdout, stderr
# endDef
def NormalizeString(string):
string = re.sub(r'(\$user\$)', username, string) # Replace meta var "username"
string = re.sub(r'(\$pass\$)', password, string) # Replace meta var "password"
# Removes/fixes leading/trailing newlines/whitespace and escapes double quotes with double quotes
string = re.sub(r'(\r\n|\r|\n)', '\n', string) # Convert all newlines to unix newlines
string = string.strip() # Remove leading/trailing whitespace/blank lines
# string = re.sub(r'(")', '""', string) # Convert double quotes to double double quotes (e.g. 'foo "bar" blah' becomes 'foo ""bar"" blah')
return string
# endDef
class Logger(object):
# Duplicate "print" output to a file.
def __init__(self, object):
self.terminal = sys.stdout
self.log = open(object, "a")
def write(self, message):
self.terminal.write(message)
self.log.write(message)
if __name__ == "__main__":
main()
ARQUIVO DE COMANDOS (exemplo)
# Ver 0.3 Command File $C hostname $C date
ARQUIVO DE SERVIDORES (exemplo)
# Host name or ip address qaectlvbosapp503