# $language = "Python" # $interface = "1.0" # ImportArbitraryDataFromFileToSecureCRTSessions_withPerfMetrics.py # # Last Modified: # # 27 Apr, 2023 # - Toggle detailed display of statistics unless explicitly turned # on by way of the g_bDisplayDetailedStats variable. # # 12 Dec, 2022 # - Toggle the Session Manager off/on at the completion of the # script to prevent the need from having to do this manually # and to "refresh" the listing of sessions available therein. # # - Allow for settings from the Default session to be copied over # to new sessions created without the native Save() API # # - Allow for designation of a special .ini file from which settings # for new sessions will be inherited; this .ini file should be # minimal, containing only those lines Copied from the Default.ini # file which you desire to be present at a minimum. This technique # speeds up creation of sessions, and allows for Default session # settings to be specified which do not match SecureCRT's "fresh # config" defaults. To utilize this mechanism, create a copy of # the Default.ini file, named "_MyDefault", and edit the .ini # file in a plain-text editor to remove all lines containing values # that you don't care about (that SecureCRT can "default" to using # fresh-config values), leaving in place only those lines containing # valuable custom default settings you want to be in place for all # imported sessions. The name of the .ini file doesn't have to be # "_MyDefault", but if you change from that, you will need to specify # the base name of your special .ini file as the value of the global # g_strDefaultSessionName variable within this script. Here is an # example minimal .ini file: # ====== # S:"Password V2"=03:b787a7fc442ef8060cd011a4e3ba4ad23e2b12345b6bcd3ec765d9ed26a2363d3b608a4297dce2126625ea652d8a15a4f18925336856f3a84efae87f4bdb05db81b1be4882eacd4ad11fad92b6ea4d22 # D:"Session Password Saved"=00000001 # B:"Normal Font v2"=00000060 # f3 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 90 01 00 00 00 00 00 01 00 00 00 01 4c 00 75 00 # 63 00 69 00 64 00 61 00 20 00 43 00 6f 00 6e 00 73 00 6f 00 6c 00 65 00 00 00 00 00 00 00 00 00 # 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 00 00 00 # B:"Narrow Font v2"=00000060 # f3 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 90 01 00 00 00 00 00 01 00 00 00 01 4c 00 75 00 # 63 00 69 00 64 00 61 00 20 00 43 00 6f 00 6e 00 73 00 6f 00 6c 00 65 00 00 00 00 00 00 00 00 00 # 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 00 00 00 # S:"Protocol Name"=SSH2 # S:"SSH2 Authentications V2"=password,publickey,keyboard-interactive,gssapi # D:"Use Global ANSI Colors"=00000001 # S:"Color Scheme"=Espresso # D:"ANSI Color"=00000001 # D:"Color Scheme Overrides Ansi Color"=00000001 # D:"[SSH2] Port"=00000016 # D:"SSH2 Common Config Version"=00000006 # ====== # # 09 Dec, 2022 # - Added the ability to toggle between API-based session existence # checking vs. file system based .ini file session exists testing # via the g_bUseOpenSessCheck global variable. Default = False, # because it's faster to check the actual file system than to use # SecureCRT's OpenSessionConfiguration() API and catch exceptions. # This change increased performance of existing session checking # by 52x and overall performace of the script by 57%. # # - Display "Finished" in reverse color so that it's more obvious # when the import operation has completed. # # 09 Dec, 2022 # - Initial Revision # # # DESCRIPTION # This sample script is designed to create sessions from a text file (.csv # format by default, but this can be edited to fit the format you have). # # To launch this script, map a button on the button bar to run this script: # https://www.vandyke.com/support/tips/buttonbar.html # # The first line of your data file should contain a comma-separated (or whatever # you define as the g_strDelimiter below) list of supported "fields" designated # by the following keywords: # ----------------------------------------------------------------------------- # session_name: The name that should be used for the session. If this field # does not exist, the hostname field is used as the session_name. # folder: Relative path for session as displayed in the Connect dialog. # hostname: The hostname or IP for the remote server. # protocol: The protocol (SSH2, SSH1, telnet, rlogin, RDP) # port: The port on which remote server is listening # username: The username for the account on the remote server # emulation: The emulation (vt100, xterm, etc.) - not for RDP sessions # description: The comment/description. Multiple lines are separated with '\r' # logon_script: Full path to Logon Script filename for session. Not for RDP. # domain: Valid only for RDP sessions. # ============================================================================= # # # As mentioned above, the first line of the data file instructs this script as # to the format of the fields in your data file and their meaning. It is not a # requirement that all the options be used. For example, notice the first line # of the following file only uses the "hostname", "username", and "protocol" # fields. Note also that the "protocol" field can be defaulted so that if a # protocol field is empty it will use the default value. # ----------------------------------------------------------------------------- # hostname,username,folder,protocol=SSH2 # 192.168.0.1,root,_imported,SSH1 # 192.168.0.2,admin,_imported,SSH2 # 192.168.0.3,root,_imported/folderA, # 192.168.0.4,root,, # 192.168.0.5,admin,_imported/folderB,telnet # ... and so on # ============================================================================= import datetime import os import platform import re import shutil import sys import time import subprocess MsgBox = crt.Dialog.MessageBox # The g_strDefaultProtocol variable will only be defined within the # ValidateFieldDesignations function if the protocol field has a default value # (e.g., protocol=SSH2), as read in from the first line of the data file. global g_strDefaultProtocol g_strDefaultProtocol = "" # The g_strDefaultFolder variable will only be defined within the # ValidateFieldDesignations function if the folder field has a default value # (e.g., folder=Site34), as read in from the first line of the data file. global g_strDefaultFolder g_strDefaultFolder = "" # The g_strDefaultUsername variable will only be defined within the # ValidateFieldDesignations function if the protocol field has a default value # (e.g., username=bobofet), as read in from the first line of the data file. global g_strDefaultUsername g_strDefaultUsername = "" # If your data file uses spaces or a character other than comma as the # delimiter, you would also need to edit the g_strDelimiter value a few lines # below to indicate that fields are separated by spaces, rather than by commas. # For example: # g_strDelimiter = " " # Using a ";" might be a good alternative for a file that includes the comma # character as part of any legitimate session name or folder name, etc. global g_strDelimiter g_strDelimiter = "," # comma #g_strDelimiter = " " # space #g_strDelimiter = ";" # semi-colon #g_strDelimiter = chr(9) # tab #g_strDelimiter = "|||" # a more unique example of a delimiter. # The g_strSupportedFields indicates which of all the possible fields, are # supported in this example script. If a field designation is found in a data # file that is not listed in this variable, it will not be imported into the # session configuration. global g_strSupportedFields g_strSupportedFields = \ "description,emulation,folder,hostname,port,protocol,session_name,username,logon_script,domain" # If you wish to overwrite existing sessions, set the # g_bOverwriteExistingSessions to True; for this example script, we're playing # it safe and leaving any existing sessions in place :). global g_bOverwriteExistingSessions g_bOverwriteExistingSessions = False strHome = os.path.expanduser("~") global g_strMyDocs g_strMyDocs = strHome + "/Documents" g_strMyDesktop = strHome + "/Desktop" global g_strHostsFile g_strHostsFile = g_strMyDocs + "/MyDataFile.csv" global g_strExampleHostsFile g_strExampleHostsFile = \ "\t\033[33mhostname,protocol,username,folder,emulation\033[0m\r\n" + \ "\t192.168.0.1,SSH2,root,Linux Machines,XTerm\r\n" + \ "\t192.168.0.2,SSH2,root,Linux Machines,XTerm\r\n" + \ "\t...\r\n" + \ "\t10.0.100.1,SSH1,admin,CISCO Routers,VT100\r\n" + \ "\t10.0.101.1,SSH1,admin,CISCO Routers,VT100\r\n" + \ "\t...\r\n" + \ "\tmyhost.domain.com,SSH2,administrator,Windows Servers,VShell\r\n" + \ "\t...\r\n" g_strExampleHostsFile = g_strExampleHostsFile.replace(",", g_strDelimiter) global g_strConfigPath, strFieldDesignations, g_vFieldsArray, vSessionInfo global strSessionName, strHostName, strPort global strUserName, strProtocol, strEmulation, strDomain global strPathForSessions, g_strLine, nFieldIndex global strSessionFileName, strFolder, nDescriptionLineCount, strDescription global g_strLastError, g_strSessionsCreated global g_nSessionsCreated, g_nDataLines, g_nCurLineNumber g_strLastError = "" g_strSessionsCreated = "" g_nSessionsCreated = 0 g_nDataLines = 0 g_nCurLineNumber = 0 global g_objReFolders, g_objReSession # Folders as specified in the data file can have # / chars since they can include sub-folder components g_objReFolders = re.compile(r'([\|\:\*\?\"\<\>])') # Session names, however, cannot have / chars g_objReSession = re.compile(r'([\|\:\*\?\"\<\>/])') global g_objReSpecialsFolders, g_objReSpecialsSession g_objReSpecialsFolders = re.compile(r'/(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])/', re.I) g_objReSpecialsSession = re.compile(r'^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])$', re.I) # Use current date/time info to avoid overwriting existing sessions by # importing sessions into a new folder named with a unique timestamp. g_strDateTimeTag = datetime.datetime.now().strftime("%Y%m%d_%H%M%S.%f")[:19] global g_bUseDefaultSessionOptions g_bUseDefaultSessionOptions = True global g_nMajorVersion, g_nMinorVersion, g_nMaintVersion strVersion = crt.Version strVersionPart = strVersion.split(" ")[0] vVersionElements = strVersionPart.split(".") g_nMajorVersion = int(vVersionElements[0]) g_nMinorVersion = int(vVersionElements[1]) g_nMaintVersion = int(vVersionElements[2]) g_objMainTab = "" g_objDebugTab = "" g_nLineStripSeconds = 0 g_nLineSplitSeconds = 0 g_nDebugSeconds = 0 g_nFieldProcessingSeconds = 0 g_nValidSessPathSeconds = 0 g_nSessionExistSeconds = 0 g_nOpenNewConfSeconds = 0 g_nSetFieldOptsSeconds = 0 g_nSetExtraOptsSeconds = 0 g_nConfigSaveSeconds = 0 g_nSessionIniMakeSeconds = 0 g_nStatsGenerationSeconds = 0 g_nDefaultValueCopySeconds = 0 g_strDebugQueue = "" g_nDebugAccumulationLimit = 4096 if sys.platform == "linux": g_nDebugAccumulationLimit *= 4 g_bUseNativeSaveAPI = False g_bUseOpenSessCheck = False g_strDefaultSessionName = "Default" # g_strDefaultSessionName = "_MyDefault" g_bDisplayDetailedStats = False ESC = "\033" CSI = ESC + "[" #---------------------------------------------------------------------------- def InitDebugTab(): global g_objDebugTab g_objDebugTab = crt.Session.ConnectInTab("/LOCALSHELL") g_objDebugTab.Caption = "Script Debug" g_objDebugTab.Session.Config.SetOption("Emulation", "Xterm") g_objDebugTab.Session.Config.SetOption("ANSI Color", 1) if not g_objDebugTab.Session.Config.GetOption("Scrollback") < 128000: g_objDebugTab.Session.Config.SetOption("Scrollback", 128000) #---------------------------------------------------------------------------- def InitMainTab(): global g_objMainTab g_objMainTab = crt.Session.ConnectInTab("/LOCALSHELL") g_objMainTab.Caption = "Script Stats" g_objMainTab.Session.Config.SetOption("Emulation", "Xterm") g_objMainTab.Session.Config.SetOption("ANSI Color", 1) #---------------------------------------------------------------------------- def Debug(strMsg, bFlush=False): global g_objDebugTab global g_nDebugSeconds global g_strDebugQueue global g_nDebugAccumulationLimit nDebugStartTime = time.time() g_strDebugQueue += strMsg if not g_objDebugTab: InitDebugTab() if (bFlush) or (len(g_strDebugQueue) >= g_nDebugAccumulationLimit): try: g_objDebugTab.Screen.Send(g_strDebugQueue, True) except: # If we get here, it means that our Debug tab somehow # got closed on us. Initialize a new one. InitDebugTab() g_objDebugTab.Screen.Send(strMsg, True) g_strDebugQueue = "" g_nDebugSeconds += time.time() - nDebugStartTime #____________________________________________________________________________ def DisplayStatus(strStats): global g_objMainTab if not g_objMainTab: InitMainTab() g_objMainTab.Screen.Send(strStats, True) #---------------------------------------------------------------------------- def FormatSecondsForDisplay(nSeconds): return str(datetime.timedelta(seconds=nSeconds)) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def GetConfigPath(): objConfig = crt.OpenSessionConfiguration("Default") # Try and get at where the configuration folder is located. To achieve # this goal, we'll use one of SecureCRT's cross-platform path # directives that means "THE path this instance of SecureCRT # is using to load/save its configuration": ${VDS_CONFIG_PATH}. # First, let's use a session setting that we know will do the # translation between the cross-platform moniker ${VDS_CONFIG_PATH} # and the actual value... say, "Upload Directory V2" strOptionName = "Upload Directory V2" # Stash the original value, so we can restore it later... strOrigValue = objConfig.GetOption(strOptionName) # Now set the value to our moniker... objConfig.SetOption(strOptionName, "${VDS_CONFIG_PATH}") # Make the change, so that the above templated name will get written # to the config... objConfig.Save() # Now, load a fresh copy of the config, and pull the option... so # that SecureCRT will convert from the template path value to the # actual path value: objConfig = crt.OpenSessionConfiguration("Default") strConfigPath = objConfig.GetOption(strOptionName) # Now, let's restore the setting to its original value objConfig.SetOption(strOptionName, strOrigValue) objConfig.Save() # Now return the config path return strConfigPath #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def ValidateFieldDesignations(strFields): global g_strDelimiter, g_strExampleHostsFile, g_strDefaultProtocol global g_vFieldsArray, g_strDefaultFolder, g_strDefaultUsername global g_strDefaultSessionName, g_strLastError if strFields.find(g_strDelimiter) == -1: if len(g_strDelimiter) > 1: strDelimiterDisplay = g_strDelimiter else: if ord(g_strDelimiter) < 33 or ord(g_strDelimiter) > 126: strDelimiterDisplay = "ASCII[{0}]".format(ord(g_strDelimiter)) else: strDelimiterDisplay = g_strDelimiter g_strLastError = ( "\r\n\033[31mDelimiter character [" + strDelimiterDisplay + "] was not found " + "in the header line of your data file:\033[0m\r\n" + " {}".format(strFields) + "\033[31m\r\n" + "\r\nScript cannot continue w/o a field delimiter." + "\r\n\r\n\033[33mChange the \033[7mg_strDelimiter\033[0;33m variable to reflect " + "the field delimiter in your input file.\r\n" + "Alternatively, make sure your input file uses the following field delimiter: " + "{}\033[0m".format(strDelimiterDisplay) ) Debug(g_strLastError) return if not strDelim == "NONE": g_strDelimiter = strDelim g_vFieldsArray = strFields.split(g_strDelimiter) if not "hostname" in [x.lower() for x in g_vFieldsArray]: strErrorMsg = ("Invalid header line in data file: " + "\r\n \033[0m{}\033[31m".format(strFields) + "\r\n\r\n'hostname' field/keyword is required.") if len(g_strDelimiter) > 1: strDelimiterDisplay = g_strDelimiter else: if ord(g_strDelimiter) < 33 or ord(g_strDelimiter) > 126: strDelimiterDisplay = "ASCII[{0}]".format(ord(g_strDelimiter)) else: strDelimiterDisplay = g_strDelimiter g_strLastError = ( "\r\n\033[31m" + strErrorMsg + "\033[0m\r\n\r\n" + "The first line of the data file is a header line " + "that must include\r\n" + "a '" + strDelimiterDisplay + "' separated list of field keywords.\r\n" + "\r\n" + "'hostname' is a required keyword." + "\r\n\r\n" + "The remainder of the lines in the file should follow the " + "\r\n" + "pattern established by the header line " + "(first line in the file)." + "\r\n" + "For example:\r\n" + g_strExampleHostsFile ) Debug(g_strLastError) return if not "protocol" in [x.lower() for x in g_vFieldsArray]: if strFields.lower().find("protocol=") == -1: # Load the default configuration and use that as the default # protocol. objConfig = crt.OpenSessionConfiguration(g_strDefaultSessionName) g_strDefaultProtocol = objConfig.GetOption("Protocol Name") for strField in g_vFieldsArray: #MsgBox("{0}\nHas 'protocol': {1}\nHas '=': {2}".format(strField, strField.find("protocol"), strField.find("="))) if strField.lower().find("protocol") > -1 and \ strField.lower().find("=") > -1: g_strDefaultProtocol = strField.split("=")[1].upper() #MsgBox(("Found a default protocol spec: {0}".format(g_strDefaultProtocol))) # Fix the protocol field since we know the default protocol # value strFields = strFields.replace(strField, "protocol") if strField.lower().find("folder") > -1 and \ strField.lower().find("=") > -1: g_strDefaultFolder = strField.split("=")[1] strFields = strFields.replace(strField, "folder") if strField.lower().find("username") > -1 and \ strField.lower().find("=") > -1: g_strDefaultUsername = strField.split("=")[1] strFields = strFields.replace(strField, "username") g_vFieldsArray = strFields.split(g_strDelimiter) return True #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def SessionExists(strSessionPath): global g_nSessionExistSeconds, g_strConfigPath, g_bUseOpenSessCheck nSessionExistStart = time.time() # Returns True if a session specified as value for strSessionPath already # exists within the SecureCRT configuration. # Returns False otherwise. bReturn = False # g_bUseOpenSessCheck allows for toggling between checking for # existing sessions using the OpenSessionConfiguration(session) # API vs. using the lower-level filesystem .ini file exists check # so as to compare which one is faster. if g_bUseOpenSessCheck: try: objTosserConfig = crt.OpenSessionConfiguration(strSessionPath) bReturn = True except Exception as objInst: bReturn = False else: strINIFilePath = os.path.join(g_strConfigPath, "Sessions", strSessionPath + ".ini") if os.path.isfile(strINIFilePath): bReturn = True else: bReturn = False g_nSessionExistSeconds += time.time() - nSessionExistStart return bReturn #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def ValidateSessionFolderComponent(strComponent, strType): # strType can be either: # folder # session strOrigComponent = strComponent strType = strType.lower() global g_objReSession, g_objReFolders # Check strComponent name for any invalid characters if strType == "folder": regexp = g_objReFolders else: regexp = g_objReSession objMatch = regexp.search(strComponent) if objMatch: strOffendingComponent = objMatch.group(1) Debug( "\r\n\033[31mError: Invalid character '{0}' ".format(strOffendingComponent) + "in {0} name \"{1}\" specified on line #{2:04d}".format( strType, strOrigComponent, g_nCurLineNumber) + ": {0}\033[0m".format(g_strLine)) return False # Now check for reserved names if we're on Windows if hasattr(sys, 'getwindowsversion'): global g_objReSpecialsFolders, g_objReSpecialsSession if strType == "folder": regexp = g_objReSpecialsFolders if not strComponent[:1] == "/": strComponent = "/{0}".format(strComponent) if not strComponent[1:] == "/": strComponent = "{0}/".format(strComponent) else: regexp = g_objReSpecialsSession objMatch = regexp.search(strComponent) if objMatch: strOffendingComponent = objMatch.group(1) Debug( "\r\n\033[31mError: Invalid {0} name ".format(strType) + "\"{0}\" specified on line #{1:04d}".format( strOrigComponent, g_nCurLineNumber) + ": {0} ---> '{1}' is a reserved name on Windows OS.\033[0m".format( g_strLine, strOffendingComponent) ) return False return True #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def Import(): global g_nMajorVersion, g_nMinorVersion, g_nMaintVersion global g_strHostsFile, strFieldDesignations, g_strDelimiter global g_strDefaultProtocol, g_nDataLines, g_strSessionsCreated, g_nSessionsCreated global g_strDefaultFolder, g_strDefaultUsername, g_strLine, g_nCurLineNumber global g_bUseDefaultSessionOptions, g_strLastError, strHostName global g_objMainTab, g_objDebugTab, g_strConfigPath, g_strDefaultSessionName global g_nLineStripSeconds global g_nLineSplitSeconds global g_nDebugSeconds global g_nFieldProcessingSeconds global g_nValidSessPathSeconds global g_nSessionExistSeconds global g_nSessionExistSeconds global g_nOpenNewConfSeconds global g_nSetFieldOptsSeconds global g_nSetExtraOptsSeconds global g_nConfigSaveSeconds global g_nSessionIniMakeSeconds global g_nStatsGenerationSeconds global g_nDefaultValueCopySeconds global g_bUseNativeSaveAPI global g_bDisplayDetailedStats g_strConfigPath = GetConfigPath() objDefConf = crt.OpenSessionConfiguration("Default") nOrigScrollback = objDefConf.GetOption("Scrollback") if not nOrigScrollback == 128000: objDefConf.SetOption("Scrollback", 128000) objDefConf.Save() bOrigScrollToClear = objDefConf.GetOption("Scroll To Clear") if bOrigScrollToClear: objDefConf.SetOption("Scroll To Clear", False) objDefConf.Save() DisplayStatus("\033[2J\033[1;1H\r Script starting ") Debug("\033[2J\033[1;1H\r Script starting ", True) if not nOrigScrollback == 128000: objDefConf.SetOption("Scrollback", nOrigScrollback) objDefConf.Save() if bOrigScrollToClear: objDefConf.SetOption("Scroll To Clear", True) objDefConf.Save() objDefConf = crt.OpenSessionConfiguration(g_strDefaultSessionName) objDefIniFile = open(os.path.join(g_strConfigPath, "Sessions", "{}.ini".format(g_strDefaultSessionName)), "r") vDefLines = list(objDefIniFile) objDefIniFile.close() g_objMainTab.Activate() strFolderOrig = g_strDefaultFolder g_strHostsFile = crt.Dialog.FileOpenDialog( "Please select the host data file to be imported.", "Open", g_strHostsFile, "CSV/Text Files (*.txt;*.csv)|*.txt;*.csv|All files (*.*)|*.*") if g_strHostsFile == "": if g_objDebugTab: g_objDebugTab.Activate() g_objDebugTab.Session.Disconnect() g_objDebugTab.Screen.SendSpecial("MENU_TAB_CLOSE") if g_objMainTab: g_objMainTab.Activate() g_objMainTab.Session.Disconnect() g_objMainTab.Screen.SendSpecial("MENU_TAB_CLOSE") return nReturn = MsgBox( "For new sessions created by this script...\r\n\r\n" + "Use settings from the \"{}\" session?\r\n".format(g_strDefaultSessionName) + "\tOr...\r\n" + "Use this script's customized options?\r\n" + " (see lines 836-880 in the script code for options & values)" + "\r\n" + "__________________________________________________\r\n" + "\r\n" + "Yes:\tUse \"{}\" Session options.\r\n".format(g_strDefaultSessionName) + "No:\tUse custom options defined in this script." + "\r\n" + "Cancel:\tExit script; let me read/modify the " + "code before I decide.", "Use \"{}\" Session options for imported sessions?".format(g_strDefaultSessionName), 3) if nReturn == 6: # Yes: g_bUseDefaultSessionOptions = True elif nReturn == 7: # No: g_bUseDefaultSessionOptions = False elif nReturn == 2: # Cancel: if g_objDebugTab: Debug("Script cancelled.") g_objDebugTab.Activate() if g_objMainTab: g_objMainTab.Session.Disconnect() g_objMainTab.Screen.SendSpecial("MENU_TAB_CLOSE") return nStartTime = time.time() bFoundHeader = False g_nCurLineNumber = 0 vSessionInfo = [] # Open our data file for reading nReadFileStart = time.time() objDataFile = open(g_strHostsFile, "r") vLines = list(objDataFile) objDataFile.close() nLinesToProcess = len(vLines) nReadFileSeconds = time.time() - nReadFileStart nSessionsPerSecond = 0 nSessionsPerMinute = 0 nTotalSecondsElapsed = 0 nPercentComplete = 0 global g_strDateTimeTag nLastDisplayTime = 0 # Iterate over each of the lines in the file, processing them one by one. for strLine in vLines: nLineStripStartTime = time.time() g_strLine = strLine.strip("\r\n") g_nLineStripSeconds += time.time() - nLineStripStartTime g_nCurLineNumber += 1 bSaveSession = False strSessionPath = "" strPort = "" strProtocol = "" strHostName = "" strUserName = "" strEmulation = "" strFolder = "" strFolderOrig = "" strDescription = "" strLogonScript = "" strDomain = "" if not bFoundHeader: strFieldDesignations = g_strLine # Validate the data file if not ValidateFieldDesignations(strFieldDesignations): if g_objDebugTab: g_objDebugTab.Activate() crt.Sleep(100) g_objDebugTab.Screen.SendSpecial("MENU_TAB_CLOSE") if g_objMainTab: g_objMainTab.Activate() g_objMainTab.Screen.Send("\r\n" + g_strLastError, True) g_objMainTab.Screen.Synchronous = False crt.Sleep(100) g_objMainTab.Session.Disconnect() return else: # Get a timer reading so that we can calculate how long it takes to import. nStartTime = time.time() nLastDisplayTime = time.time() bFoundHeader = True else: nLineSplitStartTime = time.time() vSessionInfo = g_strLine.split(g_strDelimiter) g_nLineSplitSeconds += time.time() - nLineSplitStartTime if len(vSessionInfo) < len(g_vFieldsArray): if g_strLine.strip() == "": g_strLine = "[Empty Line]" Debug("\r\n" + "\033[31mInsufficient data on line #{0:04d}: ".format(g_nCurLineNumber) + "{1}\033[0m".format(g_nCurLineNumber, g_strLine)) elif len(vSessionInfo) > len(g_vFieldsArray): Debug( "\r\n" + "\033[31m==> Number of data fields on line #" + "{0:04d} ".format(g_nCurLineNumber) + "({0:d}) ".format(len(vSessionInfo)) + "does not match the number of fields in the " + "header ({0:d}).\r\n".format( len(g_vFieldsArray)) + " This line will not be imported " + "(Does the session name have a character " + "that matches the delimiter you're using?):" + "\r\n\033[0m" + " " + g_strLine) bSaveSession = False else: # Variable used to determine if a session file should actually be # created, or if there was an unrecoverable error (and the session # should be skipped). bSaveSession = True nFieldProcStart = time.time() # Now we will match the items from the new file array to the correct # variable for the session's ini file for nFieldIndex in range(0, len(vSessionInfo)): #MsgBox("nFieldIndex: {0}\nlen(vSessionInfo):{1}\n{2}:{3}".format(nFieldIndex, len(vSessionInfo), g_vFieldsArray[nFieldIndex], vSessionInfo[nFieldIndex])) strFieldLabel = g_vFieldsArray[nFieldIndex].strip().lower() if "session_name" in strFieldLabel: strSessionName = vSessionInfo[nFieldIndex].strip() elif "logon_script" in strFieldLabel: strLogonScript = vSessionInfo[nFieldIndex].strip() elif "port" in strFieldLabel: strPort = vSessionInfo[nFieldIndex].strip() if not strPort == "": if not strPort.isdigit(): bSaveSession = False Debug("\r\n\033[31mError: Invalid port \"{0}\" specified on line #{1:04d}: {2}\033[0m".format( strPort, g_nCurLineNumber, g_strLine)) elif "protocol" in strFieldLabel: strProtocol = vSessionInfo[nFieldIndex].lower().strip() if strProtocol == "ssh2": strProtocol = "SSH2" elif strProtocol == "ssh1": strProtocol = "SSH1" elif strProtocol == "telnet": strProtocol = "Telnet" elif strProtocol == "serial" or strProtocol == "tapi": bSaveSession = False Debug("\r\n" + "\033[31mError: Unsupported protocol \"" + vSessionInfo[nFieldIndex].strip() + "\" specified on line #" + "{0:04d}: {1}\033[0m".format(g_nCurLineNumber, g_strLine)) elif strProtocol == "rlogin": strProtocol = "RLogin" elif "rdp" in strProtocol.lower(): strProtocol = "RDP" if int(g_nMajorVersion) < 9: Debug("\r\n\033[31mError: RDP support requires version 9.0+. " + "Skipped line #{0:04d}: {1}\033[0m".format( g_nCurLineNumber, g_strLine)) bSaveSession = False else: if not os.name == 'nt': Debug("\r\n\033[33mWarning: RDP is Windows-only. Skipped line #{}: {}\033[0m".format(g_nCurLineNumber, g_strLine)) bSaveSession = False elif "raw" in strProtocol.lower(): strProtocol = "Raw" else: if not g_strDefaultProtocol == "": strProtocol = g_strDefaultProtocol else: bSaveSession = False Debug("\r\n" + "\033[31mError: Invalid protocol \"" + strProtocol + "\" specified on line #" + "{0:04d}: {1}\033[0m".format(g_nCurLineNumber, g_strLine)) elif "hostname" in strFieldLabel: strHostName = vSessionInfo[nFieldIndex].strip() if strHostName == "": bSaveSession = False Debug("\r\n" + "\033[31mError: Hostname field on line #{0:04d} is empty: {1}\033[0m".format(g_nCurLineNumber, g_strLine)) elif "username" in strFieldLabel: strUserName = vSessionInfo[nFieldIndex].strip() elif "emulation" in strFieldLabel: strEmulation = vSessionInfo[nFieldIndex].lower().strip() if strEmulation == "xterm": strEmulation = "Xterm" elif strEmulation == "vt100": strEmulation = "VT100" elif strEmulation == "vt102": strEmulation = "VT102" elif strEmulation == "vt220": strEmulation = "VT220" elif strEmulation == "vt320": if g_nMajorVersion < 8: bSaveSession = False Debug("\r\n" + "\033[31mError: VT320 emulation requires v8.0+. " + "Skipped line #{0:04d}: {1}\033[0m".format( g_nCurLineNumber, g_strLine)) else: strEmulation = "VT320" elif strEmulation == "ansi": strEmulation = "ANSI" elif strEmulation == "linux": strEmulation = "Linux" elif strEmulation == "scoansi": strEmulation = "SCOANSI" elif strEmulation == "vshell": strEmulation = "VShell" elif strEmulation == "wyse50": strEmulation = "WYSE50" elif strEmulation == "wyse60": strEmulation = "WYSE60" elif strEmulation == "dumb": strEmulation = "Dumb" else: bSaveSession = False Debug("\r\n" + "\033[33mWarning: Invalid emulation \"{0}\" on line #{1:04d}: {2}\033[0m".format( strEmulation, g_nCurLineNumber, g_strLine)) elif "folder" in strFieldLabel: strFolderOrig = vSessionInfo[nFieldIndex].strip() strFolder = strFolderOrig.lower() if strFolder == "": strFolder = g_strDefaultFolder strFolderOrig = g_strDefaultFolder elif "description" in strFieldLabel: strCurDescription = vSessionInfo[nFieldIndex].strip() if strDescription == "": strDescription = strCurDescription else: strDescription = "{0}\\r{1}".format(strDescription, strCurDescription) strDescription = strDescription.replace("\\r", "\r") elif "domain" in strFieldLabel: strDomain = vSessionInfo[nFieldIndex].strip() else: # If there is an entry that the script is not set to use # in strFieldDesignations, stop the script and display a # message strMsg1 = ( "\033[31mError: Unknown field designation: {0}\n".format( g_vFieldsArray[nFieldIndex]) + "\tSupported fields are as follows:\n\n\t" + "{0}\n\n".format(g_strSupportedFields) + "For a description of the supported fields, " + "see the comments in the sample script file.\033[0m" + "") Debug("\r\n" + strMsg1, True) if g_objDebugTab: Debug("Script terminated due to error.") g_objDebugTab.Activate() if g_objMainTab: g_objMainTab.Session.Disconnect() g_objMainTab.Screen.SendSpecial("MENU_TAB_CLOSE") return g_nFieldProcessingSeconds += time.time() - nFieldProcStart # Use hostname if a session_name field wasn't present if strSessionName == "": strSessionName = strHostName nValidateSessionPathStart = time.time() if not ValidateSessionFolderComponent(strSessionName, "session"): bSaveSession = False if strFolderOrig == "": strFolderOrig = g_strDefaultFolder if not ValidateSessionFolderComponent(strFolderOrig, "folder"): bSaveSession = False g_nValidSessPathSeconds += time.time() - nValidateSessionPathStart if bSaveSession: # Canonicalize the path to the session, as needed strSessionPath = strSessionName if not strFolderOrig.strip() == "": if not strFolderOrig[1:] == "/": strSessionPath = "{0}/{1}".format(strFolderOrig, strSessionName) else: strSessionPath = "{0}/{1}".format(strFolderOrig, strSessionName) if strUserName.strip() == "": strUserName = g_strDefaultUsername # Strip any leading '/' characters from the session path strSessionPath = strSessionPath.lstrip('/') # Set this to True if you want Protocol (SSH2, SSH1, RDP, etc.) # to be included as part of the Session name: bIncludeProtocolInSessionName = False if bIncludeProtocolInSessionName: strSessionPath = "{} ({})".format(strSessionPath, strProtocol) if SessionExists(strSessionPath): if not g_bOverwriteExistingSessions: # Append a unique tag to the session name, if it already exists strFirstPart = "'{}' exists; overwrite:off; importing as: ".format( strSessionPath) strSessionPath = "{0}(import_{1})".format(strSessionPath, g_strDateTimeTag) strMsg = "\r\n{}{}".format(strFirstPart, strSessionPath) Debug(strMsg) nSessIniMakeStart = time.time() # Now: Create the session. if g_bUseNativeSaveAPI: objDefConf.SetOption("Protocol Name", strProtocol) objDefConf.Save(strSessionPath) else: # If not using the native Config.Save(newSessName) API, we do this by # creating a shell of an .ini file with just the protocol name in the # file. SecureCRT will fill in the rest as we load that config later # on and populate the remainder of the session options with the data # from the import file. strINIFilePath = os.path.join(g_strConfigPath, "Sessions", strSessionPath + ".ini") strINIParentDir = os.path.dirname(strINIFilePath) if not os.path.isdir(strINIParentDir): try: os.makedirs(strINIParentDir) except Exception as objException: Debug("\r\n\033[31mFailed to create session parent folder '{}':\r\n{}\033[0m".format(strINIParentDir, str(objException)), True) g_objDebugTab.Activate() return if os.path.isfile(strINIFilePath) and g_bOverwriteExistingSessions: Debug("\r\nOverwrite is enabled; removing existing session {}".format(strSessionPath)) os.remove(strINIFilePath) try: objFile = open(strINIFilePath, "w") if g_bUseDefaultSessionOptions: # These lines copy Default session settings to the new .ini file that was created # so that when SecureCRT loads the configuration, it includes all default values # specified in the Default session defined by the end user, rather than using # SecureCRT's "fresh install" default settings: nDefValueCopyStartTime = time.time() for strIniLine in vDefLines: if not "S:\"Protocol Name\"=" in strIniLine: objFile.write(strIniLine) g_nDefaultValueCopySeconds += time.time() - nDefValueCopyStartTime # Assign the protocol name here: objFile.write('S:"Protocol Name"={}\n'.format(strProtocol)) objFile.close() except Exception as objException: Debug("\r\n\033[31mFailed to create session INI file '{}':\r\n{}\033[0m".format(strINIFilePath, str(objException)), True) g_objDebugTab.Activate() if g_objDebugTab: Debug("Script terminated due to unexpected error.") g_objDebugTab.Activate() if g_objMainTab: g_objMainTab.Session.Disconnect() g_objMainTab.Screen.SendSpecial("MENU_TAB_CLOSE") return g_nSessionIniMakeSeconds += time.time() - nSessIniMakeStart nOpenNewSessionConfStart = time.time() objConfig = crt.OpenSessionConfiguration(strSessionPath) g_nOpenNewConfSeconds += time.time() - nOpenNewSessionConfStart nSetFieldOptionsStart = time.time() if not objConfig.GetOption("Protocol Name") == strProtocol: Debug("\r\n\033[31mError: Protocol not set. Expected \"{0}\", but got \"{1}\"\033[0m".format(strProtocol, objConfig.GetOption("Protocol Name")), True) Debug("\r\nINI Path: {}\r\nSes Path: {}".format(strINIFilePath, strSessionPath), True) g_objDebugTab.Activate() if g_objDebugTab: Debug("Script terminated due to error.") g_objDebugTab.Activate() if g_objMainTab: g_objMainTab.Session.Disconnect() g_objMainTab.Screen.SendSpecial("MENU_TAB_CLOSE") return if not strDescription == "": vDescription = strDescription.split("\r") objConfig.SetOption("Description", vDescription) if not strLogonScript == "": if not "rdp" in strProtocol.lower(): objConfig.SetOption("Script Filename V2", strLogonScript) objConfig.SetOption("Use Script File", True) else: Debug("\r\n\033[33mWarning: Logon Script is not supported for RDP sessions (line #{})\033[0m".format(g_nCurLineNumber)) if not strEmulation == "": if not "rdp" in strProtocol.lower(): objConfig.SetOption("Emulation", strEmulation) else: Debug("\r\n\033[33mWarning: Emulation is not supported for RDP sessions (line #{})\033[0m".format(g_nCurLineNumber)) if not strProtocol.lower() == "serial": if not strHostName == "": objConfig.SetOption("Hostname", strHostName) if not strUserName == "": # Handle RDP sessions uniquely since the domain setting is # tacked on to the username for such, if specified. if ("rdp" in strProtocol.lower()) and (not strDomain == ""): objConfig.SetOption("Username", "{}\{}".format(strDomain, strUserName)) else: objConfig.SetOption("Username", strUserName) if strProtocol.upper() == "SSH2": if strPort == "": strPort = 22 objConfig.SetOption("[SSH2] Port", int(strPort)) elif strProtocol.upper() == "SSH1": if strPort == "": strPort = "22" objConfig.SetOption("[SSH1] Port", int(strPort)) elif strProtocol.upper() == "TELNET": if strPort == "": strPort = "23" objConfig.SetOption("Port", int(strPort)) elif "rdp" in strProtocol.lower(): if strPort == "": strPort = "3389" objConfig.SetOption("Port", int(strPort)) g_nSetFieldOptsSeconds += time.time() - nSetFieldOptionsStart nSetExtraOptsStart = time.time() try: # Only enter this next block if the individual decided to # use this script's settings, not "Default" session's values. if (not g_bUseDefaultSessionOptions) and (not "rdp" in strProtocol.lower()): # If you don't want ANSI Color enabled for all imported sessions (regardless # of value in Default session, comment out the following line) # --------------------------------------------------------------------------- objConfig.SetOption("ANSI Color", True) objConfig.SetOption("Color Scheme", "Solarized Darcula") # Requires 8.3 or newer objConfig.SetOption("Color Scheme Overrides Ansi Color", True) # Additional "SetOption" calls desired here... Comment out those you don't # want, un-comment those you do want, and add more lines for other options # you desire to be set by default for all sessions created from the import # operation. Note: ${VDS_USER_DATA_PATH} = a cross-platform representation # of the current user's "Documents" folder. # --------------------------------------------------------------------------- objConfig.SetOption("Auto Reconnect", True) # If you desire templated log file naming to be enabled # for all imported sessions, uncommment the following 3 # lines of code: # objDefaultConfig = crt.OpenSessionConfiguration("Default") # if objDefaultConfig.GetOption("Log Filename V2") == "": # objConfig.SetOption("Log Filename V2", "${VDS_USER_DATA_PATH}\_ScrtLog(%S)_%Y%M%D_%h%m%s.%t.txt") objConfig.SetOption("Start Log Upon Connect", False) objConfig.SetOption("Rows", 60) objConfig.SetOption("Cols", 140) objConfig.SetOption("Use Word Delimiter Chars", True) if str(objConfig.GetOption("Word Delimiter Chars")) == "": objConfig.SetOption("Word Delimiter Chars", " <>()+=$%!#*") if int(objConfig.GetOption("Scrollback")) == 500: objConfig.SetOption("Scrollback", 12345) objConfig.SetOption("Key Exchange Algorithms", "diffie-hellman-group-exchange-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1") objConfig.SetOption("Idle NO-OP Check", True) objConfig.SetOption("Idle NO-OP Timeout", 60) # objConfig.SetOption("Keyword Set", "MyCiscoKeywords") # objConfig.SetOption("Highlight Color", True) # objConfig.SetOption("Highlight Reverse Video", True) # objConfig.SetOption("Ignore Window Title Change Requests", True) # objConfig.SetOption("SSH2 Authentications V2", "publickey,keyboard-interactive,password") # objConfig.SetOption("Identity Filename V2", "${VDS_USER_DATA_PATH}\Identity") # objConfig.SetOption("Firewall Name", "Session:JumpHost") # objConfig.SetOption("Firewall Name", "GlobalOptionDefinedFirewallName") objConfig.SetOption("Auth Prompts in Window", True) except Exception as objInst: Debug("\r\n\033[33mWarning: Failure detected on line #{} attempting to set option for {} session:\r\n\t{}\033[0m".format(g_nCurLineNumber, strProtocol, str(objInst))) g_nSetExtraOptsSeconds += time.time() - nSetExtraOptsStart nConfigSaveStart = time.time() objConfig.Save() g_nConfigSaveSeconds += time.time() - nConfigSaveStart if g_bDisplayDetailedStats: Debug("\r\nCreated session: {}".format(strSessionPath)) g_nSessionsCreated += 1 # Reset all variables in preparation for reading in the next line of # the hosts info file. strEmulation = "" strPort = "" strHostName = "" strFolder = "" strFolderOrig = "" strUserName = "" strSessionName = "" strDescription = "" strDomain = "" nDescriptionLineCount = 0 g_nDataLines += 1 nTotalSecondsElapsed = time.time() - nStartTime # Update stats display each second. if ((time.time() - nLastDisplayTime) >= 1): nLastDisplayTime = time.time() nStatsGenerationStart = time.time() # Display stats # First, clear the screen nTotalSecondsElapsed = time.time() - nStartTime if nTotalSecondsElapsed > 0 and g_nSessionsCreated > 0: nSessionsPerSecond = g_nSessionsCreated / nTotalSecondsElapsed nSessionsPerMinute = nSessionsPerSecond * 60 nLinesPerSecond = g_nCurLineNumber / nTotalSecondsElapsed nSecondsRemaining = (nLinesToProcess - g_nCurLineNumber) / nLinesPerSecond # nPercentComplete = (nTotalSecondsElapsed / nSecondsRemaining) nPercentComplete = (float(g_nCurLineNumber) / float(nLinesToProcess)) else: nSessionsPerSecond = 0 nSessionsPerMinute = 0 nSecondsRemaining = 0 nLinesPerSecond = g_nCurLineNumber / nTotalSecondsElapsed nLinesPerMinute = nLinesPerSecond * 60 nSecondsRemaining = (nLinesToProcess - g_nCurLineNumber) / nLinesPerSecond nPercentComplete = (float(g_nCurLineNumber) / float(nLinesToProcess)) DisplayStatus(CSI + "1;1H") strNormalStats = ( CSI + "2K" + CSI + "7m" + "Data File Stats:" + CSI + "0m" + "\r\n" + CSI + "2K" + "Data read in from file in: {} ({} total lines)".format(FormatSecondsForDisplay(nReadFileSeconds), nLinesToProcess) + "\r\n" + CSI + "2K" + "\r\n" + CSI + "2K" + CSI + "7m" + "Current Progress:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Total Lines Processed: {}/{}".format(g_nCurLineNumber, nLinesToProcess) + "\r\n" + CSI + "2K" + " Total Sessions Created: {} ({:0.2f}/sec; {:0.2f}/min)".format(g_nSessionsCreated, nSessionsPerSecond, nSessionsPerMinute) + "\r\n" + CSI + "2K" + " Total Time Elapsed: {}".format(FormatSecondsForDisplay(nTotalSecondsElapsed)[:-7]) + "\r\n" + CSI + "2K" + " Time remaining: {}".format(FormatSecondsForDisplay(nSecondsRemaining)[:-7]) + "\r\n" + CSI + "2K" + " Percent Complete: {:0.0%} ({}/{})".format(nPercentComplete, g_nCurLineNumber, nLinesToProcess) ) strDetailStats = "" if g_bDisplayDetailedStats: strDetailStats = ( "\r\n" + CSI + "2K" + "\r\n" + CSI + "2K" + CSI + "7m" + "Time Required for Specific Tasks:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Writing data to Debug Tab: {}".format(FormatSecondsForDisplay(g_nDebugSeconds)) + "\r\n" + CSI + "2K" + " Trimming lines: {}".format(FormatSecondsForDisplay(g_nLineStripSeconds)) + "\r\n" + CSI + "2K" + " Splitting line fields: {}".format(FormatSecondsForDisplay(g_nLineSplitSeconds)) + "\r\n" + CSI + "2K" + " Processing fields: {}".format(FormatSecondsForDisplay(g_nFieldProcessingSeconds)) + "\r\n" + CSI + "2K" + " Validating Session Paths: {}".format(FormatSecondsForDisplay(g_nValidSessPathSeconds)) + "\r\n" + CSI + "2K" + " Checking for existing sess: {} (Use OpenSessionConf: {})".format(FormatSecondsForDisplay(g_nSessionExistSeconds), g_bUseOpenSessCheck) + "\r\n" + CSI + "2K" + " Loading new session config: {}".format(FormatSecondsForDisplay(g_nOpenNewConfSeconds)) + "\r\n" + CSI + "2K" + " Default value copying secs: {} (Use Default Session Values: {})".format(FormatSecondsForDisplay(g_nDefaultValueCopySeconds), g_bUseDefaultSessionOptions) + "\r\n" + CSI + "2K" + " Setting sess opts (fields): {}".format(FormatSecondsForDisplay(g_nSetFieldOptsSeconds)) + "\r\n" + CSI + "2K" + " Setting sess opts (extras): {}".format(FormatSecondsForDisplay(g_nSetExtraOptsSeconds)) + "\r\n" + CSI + "2K" + " Initializing session's INI: {} (Use Native Save API: {})".format(FormatSecondsForDisplay(g_nSessionIniMakeSeconds), g_bUseNativeSaveAPI) + "\r\n" + CSI + "2K" + " Saving session settings: {}".format(FormatSecondsForDisplay(g_nConfigSaveSeconds)) + "\r\n" + CSI + "2K" + " Generating all these stats: {}".format(FormatSecondsForDisplay(g_nStatsGenerationSeconds)) + "" ) DisplayStatus("{}{}".format(strNormalStats, strDetailStats)) g_nStatsGenerationSeconds += time.time() - nStatsGenerationStart nReadLineStartTime = time.time() nPercentComplete = 1 # Display final/finished stats DisplayStatus(CSI + "1;1H") strNormalStats = ( CSI + "2K" + CSI + "7m" + "Data File Stats:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Data read in from file in: {} ({} total lines)".format(FormatSecondsForDisplay(nReadFileSeconds), nLinesToProcess) + "\r\n" + CSI + "2K" + "\r\n" + CSI + "2K" + CSI + "7m" + "Current Progress:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Total Lines Processed: {}/{}".format(g_nCurLineNumber, nLinesToProcess) + "\r\n" + CSI + "2K" + " Total Sessions Created: {} ({:0.2f}/sec; {:0.2f}/min)".format(g_nSessionsCreated, nSessionsPerSecond, nSessionsPerMinute) + "\r\n" + CSI + "2K" + " Total Time Elapsed: {}".format(FormatSecondsForDisplay(nTotalSecondsElapsed)[:-7]) + "\r\n" + CSI + "2K" + " Time remaining: " + CSI + "32;7m" + " Finished " + CSI + "0m" + "\r\n" + CSI + "2K" + " Percent Complete: {:0.0%} ({}/{})".format(nPercentComplete, g_nCurLineNumber, nLinesToProcess) ) strDetailStats = "" if g_bDisplayDetailedStats: strDetailStats = ( "\r\n" + CSI + "2K" + "\r\n" + CSI + "2K" + CSI + "7m" + "Time Required for Specific Tasks:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Writing data to Debug Tab: {}".format(FormatSecondsForDisplay(g_nDebugSeconds)) + "\r\n" + CSI + "2K" + " Trimming lines: {}".format(FormatSecondsForDisplay(g_nLineStripSeconds)) + "\r\n" + CSI + "2K" + " Splitting line fields: {}".format(FormatSecondsForDisplay(g_nLineSplitSeconds)) + "\r\n" + CSI + "2K" + " Processing fields: {}".format(FormatSecondsForDisplay(g_nFieldProcessingSeconds)) + "\r\n" + CSI + "2K" + " Validating Session Paths: {}".format(FormatSecondsForDisplay(g_nValidSessPathSeconds)) + "\r\n" + CSI + "2K" + " Checking for existing sess: {} (Use OpenSessionConf: {})".format(FormatSecondsForDisplay(g_nSessionExistSeconds), g_bUseOpenSessCheck) + "\r\n" + CSI + "2K" + " Loading new session config: {}".format(FormatSecondsForDisplay(g_nOpenNewConfSeconds)) + "\r\n" + CSI + "2K" + " Default value copying secs: {} (Use Default Session Values: {})".format(FormatSecondsForDisplay(g_nDefaultValueCopySeconds), g_bUseDefaultSessionOptions) + "\r\n" + CSI + "2K" + " Setting sess opts (fields): {}".format(FormatSecondsForDisplay(g_nSetFieldOptsSeconds)) + "\r\n" + CSI + "2K" + " Setting sess opts (extras): {}".format(FormatSecondsForDisplay(g_nSetExtraOptsSeconds)) + "\r\n" + CSI + "2K" + " Initializing session's INI: {} (Use Native Save API: {})".format(FormatSecondsForDisplay(g_nSessionIniMakeSeconds), g_bUseNativeSaveAPI) + "\r\n" + CSI + "2K" + " Saving session settings: {}".format(FormatSecondsForDisplay(g_nConfigSaveSeconds)) + "\r\n" + CSI + "2K" + " Generating all these stats: {}".format(FormatSecondsForDisplay(g_nStatsGenerationSeconds)) + "" ) DisplayStatus("{}{}".format(strNormalStats, strDetailStats)) crt.Sleep(200) crt.Screen.SendSpecial("MENU_TOGGLE_SESSION_MANAGER") crt.Sleep(175) crt.Screen.SendSpecial("MENU_TOGGLE_SESSION_MANAGER") crt.Sleep(175) crt.Screen.SendSpecial("MENU_TOGGLE_COMMAND_MANAGER") crt.Sleep(175) crt.Screen.SendSpecial("MENU_TOGGLE_COMMAND_MANAGER") crt.Sleep(175) crt.Screen.SendSpecial("MENU_TOGGLE_ACTIVE_SESSIONS") crt.Sleep(175) crt.Screen.SendSpecial("MENU_TOGGLE_ACTIVE_SESSIONS") crt.Sleep(175) if sys.platform == "linux": strOption = "Use Dockable Session Manager" bOrig = crt.Config.GetOption(strOption) crt.Config.SetOption(strOption, not bOrig) crt.Config.Save() crt.Sleep(200) crt.Config.SetOption(strOption, bOrig) crt.Config.Save() crt.Sleep(200) # Display final/finished stats again, after having toggled the Session # manager, Command Manager, and Active Sessions Manager DisplayStatus(CSI + "1;1H") strNormalStats = ( CSI + "2K" + CSI + "7m" + "Data File Stats:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Data read in from file in: {} ({} total lines)".format(FormatSecondsForDisplay(nReadFileSeconds), nLinesToProcess) + "\r\n" + CSI + "2K" + "\r\n" + CSI + "2K" + CSI + "7m" + "Current Progress:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Total Lines Processed: {}/{}".format(g_nCurLineNumber, nLinesToProcess) + "\r\n" + CSI + "2K" + " Total Sessions Created: {} ({:0.2f}/sec; {:0.2f}/min)".format(g_nSessionsCreated, nSessionsPerSecond, nSessionsPerMinute) + "\r\n" + CSI + "2K" + " Total Time Elapsed: {}".format(FormatSecondsForDisplay(nTotalSecondsElapsed)[:-7]) + "\r\n" + CSI + "2K" + " Time remaining: " + CSI + "32;7m" + " Finished " + CSI + "0m" + "\r\n" + CSI + "2K" + " Percent Complete: {:0.0%} ({}/{})".format(nPercentComplete, g_nCurLineNumber, nLinesToProcess) ) strDetailStats = "" if g_bDisplayDetailedStats: strDetailStats = ( "\r\n" + CSI + "2K" + "\r\n" + CSI + "2K" + CSI + "7m" + "Time Required for Specific Tasks:" + CSI + "0m" + "\r\n" + CSI + "2K" + " Writing data to Debug Tab: {}".format(FormatSecondsForDisplay(g_nDebugSeconds)) + "\r\n" + CSI + "2K" + " Trimming lines: {}".format(FormatSecondsForDisplay(g_nLineStripSeconds)) + "\r\n" + CSI + "2K" + " Splitting line fields: {}".format(FormatSecondsForDisplay(g_nLineSplitSeconds)) + "\r\n" + CSI + "2K" + " Processing fields: {}".format(FormatSecondsForDisplay(g_nFieldProcessingSeconds)) + "\r\n" + CSI + "2K" + " Validating Session Paths: {}".format(FormatSecondsForDisplay(g_nValidSessPathSeconds)) + "\r\n" + CSI + "2K" + " Checking for existing sess: {} (Use OpenSessionConf: {})".format(FormatSecondsForDisplay(g_nSessionExistSeconds), g_bUseOpenSessCheck) + "\r\n" + CSI + "2K" + " Loading new session config: {}".format(FormatSecondsForDisplay(g_nOpenNewConfSeconds)) + "\r\n" + CSI + "2K" + " Default value copying secs: {} (Use Default Session Values: {})".format(FormatSecondsForDisplay(g_nDefaultValueCopySeconds), g_bUseDefaultSessionOptions) + "\r\n" + CSI + "2K" + " Setting sess opts (fields): {}".format(FormatSecondsForDisplay(g_nSetFieldOptsSeconds)) + "\r\n" + CSI + "2K" + " Setting sess opts (extras): {}".format(FormatSecondsForDisplay(g_nSetExtraOptsSeconds)) + "\r\n" + CSI + "2K" + " Initializing session's INI: {} (Use Native Save API: {})".format(FormatSecondsForDisplay(g_nSessionIniMakeSeconds), g_bUseNativeSaveAPI) + "\r\n" + CSI + "2K" + " Saving session settings: {}".format(FormatSecondsForDisplay(g_nConfigSaveSeconds)) + "\r\n" + CSI + "2K" + " Generating all these stats: {}".format(FormatSecondsForDisplay(g_nStatsGenerationSeconds)) + "" ) DisplayStatus("{}{}".format(strNormalStats, strDetailStats)) if g_objDebugTab: g_objDebugTab.Screen.Send("\r\033[7;33mScroll up to see info/warning/errors\033[0m", True) Import()