Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # $language = "Python"
- # $interface = "1.0"
- # RunCommandsOnMultipleHostsAndLogResults.py
- #
- # Last Modified: 21 May, 2018
- # - If a commands file cannot be opened/read, complain "nicely"
- # rather than having the script bomb out with an exception.
- # - If parent folder specified in the log file template doesn't
- # exist, try to create it before attempting to write results
- # or errors.
- # - If unable to write to a results file or an error log file,
- # the script will continue and attempt to perform the work it
- # has been instructed to do -- regardless of ability to log
- # errors/results. Errors will still be displayed when the
- # script completes.
- # - Allow host to be specified as either existing sessions in the
- # session manager (in which case the existing session is used to
- # establish the connection), or a hostname/IP which which an ad
- # hoc connection is made. To force SecureCRT to make an ad hoc
- # connection even if an existing session is found to match the
- # host entry specified, set g_bUseExistingSessions = False below.
- # If a host matches an existing session, and the session has
- # a saved username and password (or Automate Logon option is
- # enabled, the script will not send any credentials in the Connect()
- # function defined below. Instead, it is expected that the session
- # will authenticate itself using credentials stored within the session.
- #
- # - Standardize logging to one function to avoid code duplication and
- # facilitate consistency with error reporting message format.
- #
- # - Ensure that errors are logged to the same file with "All(Errors)"
- # in the name, even if the template log file name doesn't have the
- # "IPADDRESS" substitution.
- #
- # - Only respond to Password: prompts if they appear as the left-most
- # item on the screen.
- #
- # Last Modified: 17 May, 2018
- # - Make it so that the global commands file is not needed if the hosts
- # file has a host-specific command file specified for all hosts.
- #
- # Last Modified: 11 May, 2018
- # - Add support for specifying a unique command file specific to each host.
- # To take advantage of this feature, your hosts.txt file should have this
- # format:
- # ---------------------------------------------------------------------
- # hostname1;commandfileA.txt
- # hostname2;commandfileA.txt
- # hostname3;commandfileA.txt
- # ipaddress1;commandFileB.txt
- # ipaddress2;commandFileB.txt
- # hostname4;commandFileB.txt
- # ---------------------------------------------------------------------
- # If a host-specific file is not specified for a host, the commands from
- # the file specified in the global g_strCommandsFile variable are used.
- # Host-specific command files can be specified as a fully-qualified (AKA
- # "Absolute") file path OR as a file name, in which case it is required
- # that the file exist in the same location as the hosts file.
- #
- # Last Modified: 08 May, 2018
- # - Converted from VBScript to Python as an example.
- #
- # - Errors like connection/authentication are now logged to a single
- # "AllErrors" log file (same base name as the other log file(s)).
- #
- # - Default log file name template uses both IPADDRESS and COMMAND.
- # However, the g_bLogToIndividualFilesPerCommand is set to False, and
- # the g_bLogToIndividualFilesPerHost is set to True so that one log
- # file per host will be generated by default. If a single log file for
- # all hosts and all commands is desired, simply set both:
- # g_bLogToIndividualFilesPerCommand = False
- # g_bLogToIndividualFilesPerHost = False
- #
- # - Log file names will all share the same time stamp which correlates to
- # the time at which this script was intially launched, instead of the
- # time at which each command is run. This will help in collating log
- # files in terms of instantiations of the script.
- #
- # DESCRIPTION:
- # Demonstrates how to connect to hosts and send commands, logging results of
- # each command to separate, uniquely-named files based on the host IP and/or
- # the command that has been sent. Logging behavior can be controlled either
- # by changing the variable named "g_strLogFileTemplate" (examples shown
- # below) to add/remove components or by setting one or both of the following
- # variables to True/False to get the desired logging behavior regardless of
- # the template log file name:
- # g_bLogToIndividualFilesPerHost
- # g_bLogToIndividualFilesPerCommand
- #
- # By default, this script will log commands and their results to individual
- # files - one file per each host. Here are some examples of modifying the
- # log file template.
- # Default: Log all commands to separate files based on host:
- # g_strLogFileTemplate = "{0}/##IPADDRESS--%Y-%m-%d--%H'%M'%S.txt".format(
- # g_strMyDocs)
- # --> Note: This is effectively equivalent to setting the following
- # variables to the values indicated below, WITHOUT modifying the
- # default g_strLogFileTemplate value:
- # g_bLogToIndividualFilesPerHost = True
- # g_bLogToIndividualFilesPerCommand = False
- #
- # Log Option #1: Log everything (all hosts and commands) to A SINGLE FILE.
- # g_strLogFileTemplate = "(0}/##%Y-%m-%d--%H'%M'%S.txt".format(
- # g_strMyDocs)
- # --> Note: This is effectively equivalent to setting the following
- # variables to the values indicated below, WITHOUT modifying the
- # default g_strLogFileTemplate value:
- # g_bLogToIndividualFilesPerHost = False
- # g_bLogToIndividualFilesPerCommand = False
- #
- # Log Option #2: Log hosts + commands in SEPARATE FILES; ONE FILE FOR
- # EACH COMMAND.
- # g_strLogFileTemplate = "{0}/##IPADDRESS--COMMAND--%Y-%m-%d--%H'%M'%S.txt".format(
- # g_strMyDocs)
- # --> Note: This is effectively equivalent to setting the following
- # variables to the values indicated below, WITHOUT modifying the
- # default g_strLogFileTemplate value:
- # g_bLogToIndividualFilesPerHost = True
- # g_bLogToIndividualFilesPerCommand = True
- #
- #
- # Host information is read from a file named "##hosts.txt" (located in
- # "Documents" folder)
- #
- # Commands to be run on each remote host are read in from a file named
- # "##commands.txt" (also located in "Documents" folder)
- #
- # This script does not interfere with a session's logging settings; instead,
- # the crt.Screen.ReadString() method is used to capture the output of a
- # command, and then native python code is used to write the captured data
- # to a file.
- #
- import os, platform, time, re, errno
- # -----------------------------------------------------------------------------
- def GetDocumentsFolder():
- objConfig = crt.OpenSessionConfiguration("Default")
- strOptionName = "Upload Directory V2"
- strOrigValue = objConfig.GetOption(strOptionName)
- objConfig.SetOption(strOptionName, "${VDS_USER_DATA_PATH}")
- objConfig.Save()
- objConfig = crt.OpenSessionConfiguration("Default")
- strMyDocs = objConfig.GetOption(strOptionName)
- objConfig.SetOption(strOptionName, strOrigValue)
- objConfig.Save()
- return strMyDocs.replace("\\", "/")
- g_strMyDocs = GetDocumentsFolder()
- # ##hosts.txt and ##commands.txt files are located in the current user's
- # ##MyDocuments folder. Hard-code to different paths as your needs dictate.
- g_strHostsFile = g_strMyDocs + "/##hosts.txt"
- g_strCommandsFile = g_strMyDocs + "/##commands.txt"
- # Template used for formulating the name of the results file in which the
- # command output will be saved. You can choose to arrange the various
- # components (i.e. "IPADDRESS", "COMMAND", "%Y", "%m", "%d", "%H", etc.) of
- # the log file name into whatever order you want it to be.
- g_strLogFileTemplate = (g_strMyDocs +
- "/Log/##IPADDRESS-COMMAND-%Y-%m-%d--%H'%M'%S.txt")
- g_bLogToIndividualFilesPerHost = True
- g_bLogToIndividualFilesPerCommand = False
- # Add Time stats to the log file name based on the Template
- # defined by the script author. We do this here at the top
- # of the script so that even when logging to multiple hosts
- # in separate files, the time stamps will all show up the
- # same for easy sorting/grouping in your file explorer/finder.
- g_strLogFileTemplate = time.strftime(g_strLogFileTemplate, time.localtime())
- # Comment character allows for comments to exist in either the ##host.txt or
- # ##commands.txt files. Lines beginning with this character will be ignored.
- g_strComment = "#"
- g_vHosts = []
- g_vCommands = []
- g_nHostCount = 0
- # If connecting through a proxy is required, comment out the second statement
- # below, and modify the first statement below to match the name of the firewall
- # through which you're connecting (as defined in global options within
- # SecureCRT)
- g_strFirewall = " /FIREWALL=myFireWallName "
- g_strFirewall = ""
- # Username for authenticating to the remote system
- g_strUsername = "user"
- # Password for authenticating to the remote system
- g_strPassword = "p4$$w0rd"
- # Global variable for housing details of any errors that might be encountered
- global g_strError
- global g_objNewTab
- global g_strHost
- global g_vDefaultCommands, g_nDefaultCommandCount, g_bDefaultCommandsFileExists
- g_vDefaultCommands = []
- g_nDefaultCommandCount = 0
- g_bDefaultCommandsFileExists = False
- global g_bUseExistingSessions
- g_bUseExistingSessions = True
- # -----------------------------------------------------------------------------
- def MainSub():
- # Create arrays in which lines from the hosts and commands files will be
- # stored.
- global g_vHosts, g_vCommands, g_nDefaultCommandCount, g_vDefaultCommands
- # Create variables for storing information about the lines read from the
- # file
- g_nHostCount = 0
- nCommandCount = 0
- global g_strHostsFile, g_strComment, g_strHost, g_objNewTab, g_strError
- # Call the ReadDataFromFile() function defined in this script. It will
- # read in the hosts file and populate an array with non-comment lines that
- # will represent the hosts to which connections will be made later on.
- vReturnValsHostsFile = ReadDataFromFile(g_strHostsFile, g_strComment)
- if not vReturnValsHostsFile[0]:
- DisplayMessage("No hosts were found in file: \r\n " + g_strHostsFile)
- return
- g_vHosts = vReturnValsHostsFile[1]
- g_nHostCount = vReturnValsHostsFile[2]
- # crt.Dialog.MessageBox("Read in {0} hosts".format(g_nHostCount))
- strErrors = ""
- strSuccesses = ""
- # If the g_strCommandsFile path exists, load those commands into a
- # global array and populate global variables for use when a host needs
- # to send commands from this file. If a line in the hosts file contains
- # a host-specific commands file, this script will load those as needed.
- # Call the ReadDataFromFile() function to populate the array of commands
- # that will be sent for this host.
- if os.path.isfile(g_strCommandsFile):
- g_bDefaultCommandsFileExists = True
- vReturnValsCmdsFile = ReadDataFromFile(g_strCommandsFile, g_strComment)
- if not vReturnValsCmdsFile[0]:
- strError = (
- "WARNING: Default commands file does not contain any " +
- "commands: " + g_strCommandsFile + ".\r\n" +
- "Any lines in the hosts file which don't include a " +
- "commands file specification will fail.")
- strErrors = CaptureError(strErrors, strError)
- else:
- g_vDefaultCommands = vReturnValsCmdsFile[1]
- g_nDefaultCommandCount = vReturnValsCmdsFile[2]
- else:
- g_bDefaultCommandsFileExists = False
- # Before attempting any connections, ensure that the "Auth Prompts In
- # Window" option in the Default session is already enabled. If not, prompt
- # the user to have the script enable it automatically before continuing.
- # Before continuing on with the script, ensure that the session option
- # for handling authentication within the terminal window is enabled
- objConfig = crt.OpenSessionConfiguration("Default")
- bAuthInTerminal = objConfig.GetOption("Auth Prompts In Window")
- if not bAuthInTerminal:
- strMessage = ("" +
- "The 'Default' session (used for all ad hoc " +
- "connections) does not have the 'Display logon prompts in " +
- "terminal window' option enabled, which is required for this " +
- "script to operate successfully.\r\n\r\n")
- if not PromptYesNo(
- strMessage +
- "Would you like to have this script automatically enable this " +
- "option in the 'Default' session so that next time you run " +
- "this script, the option will already be enabled?"):
- return
- # User answered prompt with Yes, so let's set the option and save
- objConfig.SetOption("Auth Prompts In Window", True)
- objConfig.Save()
- # Iterate through each element of our g_vHosts array...
- for nIndex in range(0, g_nHostCount):
- # Arrays are indexed starting at 0 (zero)
- # Store the current host in a variable so we don't have to remember
- # what "g_vHosts(nIndex)" means.
- g_strHost = g_vHosts[nIndex]
- # Exit the loop if the host name is empty (this means we've
- # reached the end of our array
- if g_strHost == "":
- return
- strCommandsFilename = ""
- bContinue = True
- if ";" in g_strHost:
- vHostElems = g_strHost.split(";")
- g_strHost = vHostElems[0]
- strCommandsFilename = vHostElems[1]
- if strCommandsFilename == "":
- strCommandsFilename = g_strCommandsFile
- strCommandsFilenameOrig = strCommandsFilename
- if not os.path.isfile(strCommandsFilename):
- # Check if the file path is relative to where hosts.txt
- # lives
- strCommandsFilename = os.path.join(
- os.path.dirname(os.path.normpath(g_strHostsFile)),
- strCommandsFilename)
- if not os.path.isfile(strCommandsFilename):
- strError = (
- "Host-specific command file not found for host '" +
- g_strHost + "': " + strCommandsFilenameOrig + " (" + strCommandsFilename + ")")
- strErrors = CaptureError(strErrors, strError)
- bContinue = False
- if bContinue:
- g_strError = ""
- # Now call the ReadDataFromFile() function for the commands file.
- vReturnValsCmdsFile = ReadDataFromFile(strCommandsFilename, g_strComment)
- g_vCommands = vReturnValsCmdsFile[1]
- nCommandCount = vReturnValsCmdsFile[2]
- if not vReturnValsCmdsFile[0]:
- strError = (
- "Error attempting to read host-specific file for host '" +
- g_strHost + "': " + g_strError)
- strErrors = CaptureError(strErrors, strError)
- bContinue = False
- else:
- # If we've had any host-specific command file change, we'll need
- # to use the common commands file to avoid running the last-known
- # host-specific commands with this new host that doesn't have a
- # commands file specified; use the default commands file.
- # Call the ReadDataFromFile() function to populate the array of commands
- # that will be sent for this host.
- if not g_bDefaultCommandsFileExists:
- strError = (
- "While working on host '" +
- g_strHost + "... could not send any commands; " +
- "default commands file was not found. Check the " +
- "g_strCommandsFile variable; it should point to " +
- "a valid commands file. Alternatively, edit " +
- "your hosts file and make sure it contains a " +
- "host-specific commands file.")
- strErrors = CaptureError(strErrors, strError)
- bContinue = False
- elif g_nDefaultCommandCount == 0:
- strError = (
- "While working on host '" +
- g_strHost + "... could not send any commands; default " +
- "commands file is empty.")
- strErrors = CaptureError(strErrors, strError)
- bContinue = False
- else:
- # We have a valid default commands file and it has commands
- # in it. Let's use it.
- g_vCommands = g_vDefaultCommands
- nCommandCount = g_nDefaultCommandCount
- if bContinue:
- # Build up a string containing connection information and options.
- # /ACCEPTHOSTKEYS should only be used if you suspect that there might be
- # hosts in the hosts.txt file to which you haven't connected before, and
- # therefore SecureCRT hasn't saved out the SSH2 server's host key. If
- # you are confused about what a host key is, please read through the
- # white paper:
- # http://www.vandyke.com/solutions/host_keys/index.html
- #
- # A best practice would be to connect manually to each device,
- # verifying each server's hostkey individually before running this
- # script.
- #
- # If you want to authenticate with publickey authentication instead of
- # password, in the assignment of strConnectString below, replace:
- # " /AUTH password,keyboard-interactive /PASSWORD " + g_strPassword + _
- # with:
- # " /AUTH publickey /I \"full_path_to_private_key_file\" " + _
- if g_bUseExistingSessions and SessionExists(g_strHost):
- strConnectString = ("/S {0}".format(g_strHost))
- else:
- strConnectString = ("" +
- g_strFirewall +
- " /SSH2 " +
- " /L " + g_strUsername +
- " /AUTH password,keyboard-interactive /PASSWORD " + g_strPassword +
- " " + g_strHost)
- #crt.Dialog.MessageBox(strConnectString)
- # Call the Connect() function defined below in this script. It handles
- # the connection process, returning success/fail.
- if not Connect(strConnectString):
- strError = "Failed to connect to " + g_strHost + ": " + g_strError
- strErrors = CaptureError(strErrors, strError)
- else:
- # If we get to this point in the script, we're connected (including
- # authentication) to a remote host successfully.
- g_objNewTab.Screen.Synchronous = True
- g_objNewTab.Screen.IgnoreEscape = True
- # Once the screen contents have stopped changing (polling every
- # 350 milliseconds), we'll assume it's safe to start interacting
- # with the remote system.
- if not WaitForScreenContentsToStopChanging(250):
- strError = ("Error: " +
- "Failed to detect remote ready status for host: " +
- "{0}. {1}".format(g_strHost, g_strError))
- strErrors = CaptureError(strErrors, strError)
- else:
- # Get the shell prompt so that we can know what to look for when
- # determining if the command is completed. Won't work if the
- # prompt is dynamic (e.g. changes according to current working
- # folder, etc)
- nRow = g_objNewTab.Screen.CurrentRow
- strPrompt = g_objNewTab.Screen.Get(
- nRow,
- 0,
- nRow,
- g_objNewTab.Screen.CurrentColumn - 1)
- strPrompt = strPrompt.strip(" \r\n")
- # crt.Dialog.MessageBox("Here is the prompt: {0}".format(strPrompt))
- # Send each command one-by-one to the remote system:
- for strCommand in g_vCommands:
- if strCommand == "":
- break
- # Send the command text to the remote
- # crt.Dialog.MessageBox("About to send cmd: {0}".format(str(strCommand)))
- g_objNewTab.Screen.Send("{0}\r".format(strCommand))
- # Wait for the command to be echo'd back to us.
- g_objNewTab.Screen.WaitForString(strCommand)
- # Since we don't know if we're connecting to a cisco switch or a
- # linux box or whatever, let's look for either a Carriage Return
- # (CR) or a Line Feed (LF) character in any order.
- vWaitFors = ["\r", "\n"]
- bFoundEOLMarker = False
- while True:
- # Call WaitForStrings, passing in the array of possible
- # matches.
- g_objNewTab.Screen.WaitForStrings(vWaitFors, 1)
- # Determine what to do based on what was found)
- nMatchIndex = g_objNewTab.Screen.MatchIndex
- if nMatchIndex == 0: # Timed out
- break
- if nMatchIndex in [1,2]: # found either CR or LF
- # Check to see if we've already seen the other
- # EOL Marker
- if bFoundEOLMarker:
- break
- # If this is the first time we've been through
- # here, indicate as much, and then loop back up
- # to the top and try to find the other EOL
- # marker.
- bFoundEOLMarker = True
- # Now that we know the command has been sent to the remote
- # system, we'll begin the process of capturing the output of
- # the command.
- strResult = ""
- # Use the ReadString() method to get the text displayed
- # while the command was runnning. Note that the ReadString
- # usage shown below is not documented properly in SecureCRT
- # help files included in SecureCRT versions prior to 6.0
- # Official. Note also that the ReadString() method captures
- # escape sequences sent from the remote machine as well as
- # displayed text. As mentioned earlier in comments above,
- # if you want to suppress escape sequences from being
- # captured, set the Screen.IgnoreEscape property = True.
- strResult = g_objNewTab.Screen.ReadString(strPrompt)
- # Set the log file name based on the remote host's IP
- # address and the command we're currently running. We also
- # add a date/timestamp to help make each filename unique
- # over time.
- strLogFile = g_strLogFileTemplate.replace(
- "IPADDRESS",
- g_objNewTab.Session.RemoteAddress)
- if g_bLogToIndividualFilesPerHost:
- strLogFile = g_strLogFileTemplate
- if "IPADDRESS" in g_strLogFileTemplate:
- strLogFile = g_strLogFileTemplate.replace(
- "IPADDRESS", g_objNewTab.Session.RemoteAddress)
- else:
- strLogFile = os.path.join(
- os.path.dirname(g_strLogFileTemplate),
- g_objNewTab.Session.RemoteAddress +
- os.path.basename(g_strLogFileTemplate))
- else:
- if "IPADDRESS" in g_strLogFileTemplate:
- strLogFile = g_strLogFileTemplate.replace(
- "IPADDRESS",
- "ALLHOSTS")
- else:
- strLogFile = g_strLogFileTemplate
- if not "ALLHOSTS" in g_strLogFileTemplate:
- strLogFile = os.path.join(
- os.path.dirname(g_strLogFileTemplate),
- "ALLHOSTS_" +
- os.path.basename(g_strLogFileTemplate))
- if "COMMAND" in strLogFile:
- if g_bLogToIndividualFilesPerCommand:
- # Replace any illegal characters that might have been
- # introduced by the command we're running (e.g. if the
- # command had a path or a pipe in it)
- strCleanCmd = strCommand.replace('/', "[SLASH]")
- strCleanCmd = strCleanCmd.replace('\\', "[BKSLASH]")
- strCleanCmd = strCleanCmd.replace(':', "[COLON]")
- strCleanCmd = strCleanCmd.replace( '*', "[STAR]")
- strCleanCmd = strCleanCmd.replace( '?', "[QUESTION]")
- strCleanCmd = strCleanCmd.replace( '"', "[QUOTE]")
- strCleanCmd = strCleanCmd.replace( '<', "[LT]")
- strCleanCmd = strCleanCmd.replace( '>', "[GT]")
- strCleanCmd = strCleanCmd.replace( '|', "[PIPE]")
- strLogFile = strLogFile.replace("COMMAND", strCleanCmd)
- else:
- strLogFile = strLogFile.replace("COMMAND", "ALLCMDS")
- if not os.path.isdir(os.path.dirname(strLogFile)):
- try:
- os.makedirs(os.path.dirname(strLogFile))
- except Exception, objInst:
- if objInst.errno != errno.EEXIST:
- strErrors = CaptureError(strErrors,
- "Failed to create directory " +
- "structure for output files: " +
- str(objInst))
- try:
- with open(strLogFile, "a") as objFile:
- # If you do not want the command logged along with the results,
- # command out the following script statement:
- objFile.write(
- "=" * 80 + "\n" +
- "Results of command " +
- "'{0}' sent to host '{1}':\n".format(strCommand,
- g_strHost) + "-" * 80)
- # Write out the results of the command and a separator
- objFile.write("\n{0}\n".format(strResult))
- except Exception, objInst:
- strErrors = CaptureError(strErrors,
- "Failed to open file for " +
- "writing results of command '" + strCommand +
- "': " + str(objInst))
- # Now disconnect from the current machine before connecting to
- # the next machine
- while g_objNewTab.Session.Connected:
- g_objNewTab.Session.Disconnect()
- crt.Sleep(100)
- strSuccesses += "\n{0}".format(g_strHost)
- # End of WaitForScreenContentsToStopChanging()
- # End of Connect()
- # End of if bContinue
- # End of 'for nIndex in range(...)'
- strMsg = "Commands were sent to the following hosts:\n{0}".format(
- strSuccesses)
- if strErrors <> "":
- strMsg += ("\n\nErrors were encountered connecting to " +
- "these hosts:\n{0}".format(strErrors))
- DisplayMessage(strMsg)
- if strErrors <> "":
- if crt.Dialog.MessageBox(
- "Copy these errors to the clipboard?", "Copy to clipboard?", 4) == 6:
- crt.Clipboard.Text = strErrors
- # End of def MainSub()
- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- def ReadDataFromFile(strFile, strComment):
- # strFile: IN parameter specifying full path to data file.
- # strComment: IN parameter specifying string that preceded
- # by 0 or more space characters will indicate
- # that the line should be ignored.
- # Return value:
- # Returns an array where the elements of the array have the following
- # meanings.
- # vParams[0]: OUT parameter indicating success/failure of this
- # function
- # vParams[1]: OUT parameter (destructive) containing array
- # of lines read in from file.
- # vParams[2]: OUT parameter integer indicating number of lines read
- # in from file.
- # vParams[3]: OUT parameter indicating number of comment/blank lines
- # found in the file
- global g_strError
- strFile = strFile.replace("\\", "/")
- # Set up return values
- # Start of with an empty list/array:
- vLines = []
- nLineCount = 0
- nCommentLines = 0
- vOutParams = [False, vLines, nLineCount, nCommentLines]
- # Check to see if the file exists... if not, bail early.
- if not os.path.exists(strFile):
- DisplayMessage("File not found: {0}".format(strFile))
- g_strError = "File not found: {0}".format(strFile)
- return vOutParams
- # Used for detecting comment lines, a regular expression object
- p = re.compile("(^[ \\t]*(?:{0})+.*$)|(^[ \\t]+$)|(^$)".format(strComment))
- try:
- # Open a TextStream Object to the file...
- objFile = open(strFile, 'r')
- except Exception as objInst:
- g_strError = "Unable to open '{0}' for reading: {1}".format(
- strFile, str(objInst))
- return vOutParams
- # Read in just the first byte so that we can tell if the encoding isn't right.
- # better to display a warning than to have things go awry and not really know
- # why...
- try:
- b = str(objFile.read(1))
- except Exception as objInst:
- g_strError = "Unable to read data from file '{0}': {1}".format(
- strFile, strObjInst)
- if len(b) < 1:
- # if the file is empty...
- g_strError = "File is empty: {0}".format(strFile)
- return vOutParams
- if ord(b) == 239:
- objFile.close()
- strMsg = "UTF-8 format is not supported. File must be saved in ANSI format:\r\n{0}".format(strFile)
- DisplayMessage(strMsg)
- g_strError = strMsg
- return vOutParams
- elif ord(b) == 255 or ord(b) == 254:
- objFile.close()
- strMsg = "Unicode format is not supported. File must be saved in ANSI format:\r\n{0}".format(strFile)
- DisplayMessage(strMsg)
- g_strError = strMsg
- return vOutParams
- else:
- # We know we're likely an ANSI encoded file... close the file
- # and re-open so that we don't lose the first byte
- objFile.close()
- objFile = open(strFile, 'r')
- for strLine in objFile:
- strLine = strLine.strip(' \r\n')
- # Look for comment lines that match the pattern
- # [whitespace][strComment]
- if p.match(strLine):
- # Line matches our comment pattern... ignore it
- nCommentLines += 1
- else:
- vLines.append(strLine)
- nLineCount += 1
- # Check to make sure we actually have commands to run
- if nLineCount < 1:
- vOutParams = [False, vLines, nLineCount, nCommentLines]
- g_strError = 'No valid lines found in file: {0}'.format(strFile)
- return vOutParams
- # crt.Dialog.MessageBox("Read in {0} lines from file: {1}".format(nLineCount, strFile))
- vOutParams = [True, vLines, nLineCount, nCommentLines]
- return vOutParams
- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- def Connect(strConnectInfo):
- # Connect in a new tab to the host specified
- global g_objNewTab, g_strError, g_strHost, g_strUsername
- bWaitForAuthToCompleteBeforeReturning = False
- bLetCallerDetectAndHandleConnectionErrors = True
- try:
- g_objNewTab = crt.Session.ConnectInTab(
- strConnectInfo,
- bWaitForAuthToCompleteBeforeReturning,
- bLetCallerDetectAndHandleConnectionErrors)
- except Exception, objInst:
- g_strError = "Connection attempt raised an exception.\r\n{0}".format(
- str(objInst))
- return False
- if g_objNewTab.Session.Connected <> True:
- if crt.GetLastErrorMessage() == "":
- g_strError = "Unknown error"
- #crt.Dialog.MessageBox(g_strError)
- else:
- g_strError = str(crt.GetLastErrorMessage())
- #crt.Dialog.MessageBox(g_strError)
- # You're not allowed to close the script tab (the tab in which the
- # script was launched oringinally), so only try if the new tab really
- # was a new tab -- not just reusing a disconnected tab.
- if g_objNewTab.Index <> crt.GetScriptTab().Index:
- g_objNewTab.Close()
- return False
- # Make sure the new tab is "Synchronous" so we can properly wait/send/etc.
- g_objNewTab.Screen.Synchronous = True
- # Handle authentication in the new tab using the new tab's object reference
- # instead of 'crt'
- nAuthTimeout = 10 # seconds
- # Modify the "$", the "]#", and/or the "->" in the array below to reflect
- # the variety of legitimate shell prompts you would expect to see when
- # authentication is successful to one of your remote machines.
- vPossibleShellPrompts = [
- "ogin:",
- "name:",
- "sword:",
- "Login incorrect",
- "authentication failed.",
- "$",
- "#",
- ">"]
- bSendPassword = True
- bSendUsername = True
- if SessionExists(g_strHost):
- objConfig = crt.OpenSessionConfiguration(g_strHost)
- if objConfig.GetOption("Use Login Script") == True:
- bSendUsername = False
- bSendPassword = False
- if objConfig.GetOption("Session Password Saved") == True:
- bSendPassword = False
- if objConfig.GetOption("Username") <> "":
- bSendUsername = False
- while True:
- try:
- g_objNewTab.Screen.WaitForStrings(vPossibleShellPrompts, nAuthTimeout)
- # This Select..Case statement represents somewhat of a "state machine"
- # in which the value of Screen.MatchIndex represents the index of the
- # array of strings we told WaitForStrings() to look for. Based on this
- # index, we know what action needs to be performed next.
- if g_objNewTab.Screen.MatchIndex == 0:
- # ...time out condition...
- g_strError = ("Authentication timed out!\r\n" +
- "(Or you forgot to add a case for a successful shell " +
- "prompt in the vPossibleShellPrompts array)")
- # Disconnect from the host so that we can reuse the disconnected
- # tab for the next connection in the loop
- while g_objNewTab.Session.Connected:
- g_objNewTab.Session.Disconnect()
- crt.Sleep(100)
- #crt.Dialog.MessageBox(g_strError)
- return False
- elif g_objNewTab.Screen.MatchIndex == 1:
- if not bSendUsername:
- continue
- #... "ogin: "...
- # Send the username only if it makes sense based on
- # the current position of the cursor:
- if g_objNewTab.Screen.CurrentColumn <= len("Login: "):
- g_objNewTab.Screen.Send(g_strUsername + "\r")
- elif g_objNewTab.Screen.MatchIndex == 2:
- if not bSendUsername:
- continue
- # ..."name:"...
- # Send the username, but only if it makes sense based on
- # the current position of the cursor:
- if g_objNewTab.Screen.CurrentColumn <= len("Username: "):
- g_objNewTab.Screen.Send(g_strUsername + "\r")
- elif g_objNewTab.Screen.MatchIndex == 3:
- if not bSendPassword:
- continue
- # ..."sword:"...
- # Send the password
- if g_objNewTab.Screen.CurrentColumn <= len("Password: "):
- g_objNewTab.Screen.Send(g_strPassword + "\r")
- elif (g_objNewTab.Screen.MatchIndex == 4 or
- g_objNewTab.Screen.MatchIndex == 5):
- # ..."Login incorrect", "authentication failed."...
- g_strError = (
- "Password authentication to '" + g_strHost + "' as user '" +
- g_strUsername + "' failed.\r\n\r\n" +
- "Please specify the correct password for user " +
- "'" + g_strUsername + "'")
- # Disconnect from the host so that we can reuse the disconnected
- # tab for the next connection in the loop
- while g_objNewTab.Session.Connected:
- g_objNewTab.Session.Disconnect()
- crt.Sleep(100)
- #crt.Dialog.MessageBox(g_strError)
- return False
- elif (g_objNewTab.Screen.MatchIndex == 6 or
- g_objNewTab.Screen.MatchIndex == 7 or
- g_objNewTab.Screen.MatchIndex == 8):
- #...6,7,8 # "$", "#", or ">" <-- Shell prompt means auth success...
- g_objNewTab.Session.SetStatusText("Connected to " + g_strHost +
- " as " + g_strUsername)
- break
- else:
- g_strError = ("Ooops! Looks like you forgot to add code " +
- "to handle the '{0}' prompt (vPossibleShellPrompts[{1}]).".format(
- vPossibleShellPrompts[g_objNewTab.Screen.MatchIndex - 1],
- g_objNewTab.Screen.MatchIndex - 1) +
- "\r\n" +
- "\r\n" +
- "Modify your script code's 'Connect()' function " +
- "to have a statment like this for the corresponding " +
- "shell prompt:\n\n" +
- "elif g_objNewTab.Screen.MatchIndex == " +
- "{0}:".format(g_objNewTab.Screen.MatchIndex) +
- "\n # put your code to handle this case here" +
- "\n # ." +
- "\n # ." +
- "\n # .")
- #crt.Dialog.MessageBox(g_strError)
- while g_objNewTab.Session.Connected:
- g_objNewTab.Session.Disconnect()
- crt.Sleep(100)
- return False
- except Exception, objInst:
- # Most likely if there was a problem here, it would have been caused by
- # an unexpected disconnect occurring while WaitForStrings() was running
- # as called above. If error, set the global description variable and
- # then exit the function.
- g_strError = "{0}\n{1}".format(str(crt.GetLastErrorMessage()), str(objInst))
- # Ensure that the session is disconnected before we exit this
- # function. If there are subsequent hosts to loop through, we don't
- # want a connected tab interfering with the next host's connection
- # attempts
- while g_objNewTab.Session.Connected:
- g_objNewTab.Session.Disconnect()
- crt.Sleep(100)
- return False
- # If the code gets here, then we must have been successful connecting and
- # authenticating to the remote machine; return the value of True
- # for the Connect() function.
- return True
- # -----------------------------------------------------------------------------
- def CaptureError(strErrors, strError):
- global g_strLogFileTemplate
- if strErrors == "":
- strErrors = strError
- else:
- strErrors = "{0}\r\n{1}".format(strErrors, strError)
- strLogFile = g_strLogFileTemplate
- if "IPADDRESS" in strLogFile:
- strLogFile = strLogFile.replace("IPADDRESS", "All(Errors)")
- else:
- strLogFile = os.path.join(os.path.dirname(strLogFile),
- "All(Errors)" + os.path.basename(strLogFile))
- strLogFile = strLogFile.replace("COMMAND", "")
- if not os.path.isdir(os.path.dirname(strLogFile)):
- try:
- os.makedirs(os.path.dirname(strLogFile))
- except Exception, objInst:
- if objInst.errno != errno.EEXIST:
- if not "Failed to create" in strError:
- strErrors += ("\r\nFailed to create directory " +
- "structure for log file: " +
- str(objInst))
- try:
- with open(strLogFile, "a") as objFile:
- objFile.write("=" * 80)
- objFile.write("\r\n{0}\r\n".format(strError))
- except Exception as objInst:
- if not (
- "Failed to create" in strError or
- "Failed to open" in strError):
- strErrors += "\r\nFailed to open file for writing: {1}".format(
- strLogFile, str(objInst))
- return strErrors
- # -----------------------------------------------------------------------------
- def WaitForScreenContentsToStopChanging(nMsDataReceiveWindow):
- # This function relies on new data received being different from the
- # data that was already received. It won't work if, as one example, you
- # have a screenful of 'A's and more 'A's arrive (because one screen
- # "capture" will look exactly like the previous screen "capture").
- global g_objNewTab
- # Store Synch flag for later restoration
- bOrig = g_objNewTab.Screen.Synchronous
- # Turn Synch off since speed is of the essence; we'll turn it back on (if
- # it was already on) at the end of this function
- g_objNewTab.Screen.Synchronous = False
- # Be "safe" about trying to access Screen.Get(). If for any reason we
- # get disconnected, we don't want the script to error out on the problem
- # so we'll just return false and handle writing something to our log
- # file for this host.
- try:
- strLastScreen = g_objNewTab.Screen.Get(1,1,g_objNewTab.Screen.Rows,g_objNewTab.Screen.Columns)
- while True:
- crt.Sleep(nMsDataReceiveWindow)
- # Be "safe" about trying to access Screen.Get(). If for any reason we
- # get disconnected, we don't want the script to error out on the problem
- # so we'll just return false and handle writing something to our log
- # file for this host.
- strNewScreen = g_objNewTab.Screen.Get(1,1,g_objNewTab.Screen.Rows, g_objNewTab.Screen.Columns)
- if strNewScreen == strLastScreen:
- break
- strLastScreen = strNewScreen
- # Restore the Synch setting
- g_objNewTab.Screen.Synchronous = bOrig
- return True
- except Exception, objInst:
- # Most likely if there was a problem here, it would have been caused by
- # an unexpected disconnect occurring while WaitForStrings() was running
- # as called above. If error, set the global description variable and
- # then exit the function.
- g_strError = crt.GetLastErrorMessage()
- # Ensure that the session is disconnected before we exit this
- # function. If there are subsequent hosts to loop through, we don't
- # want a connected tab interfering with the next host's connection
- # attempts
- while g_objNewTab.Session.Connected:
- g_objNewTab.Session.Disconnect()
- crt.Sleep(100)
- g_objNewTab.Screen.Synchronous = bOrig
- return False
- # -----------------------------------------------------------------------------
- def PromptYesNo(strText):
- vbYesNo = 4
- return crt.Dialog.MessageBox(strText, "SecureCRT", vbYesNo)
- # -----------------------------------------------------------------------------
- def DisplayMessage(strText):
- crt.Dialog.MessageBox(strText)
- #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- def SessionExists(strSessionPath):
- # Returns True if a session specified as value for strSessionPath already
- # exists within the SecureCRT configuration.
- # Returns False otherwise.
- try:
- objTosserConfig = crt.OpenSessionConfiguration(strSessionPath)
- return True
- except Exception as objInst:
- return False
- # Call the main subroutine named "MainSub"
- MainSub()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement