# $language = "Python" # $interface = "1.0" # ChangeHostnameAndPortForAllSessions.py # Last Modified: # 11 Aug, 2020 # - Add support for exclusion list via 'exclude' # argument. For example, "exclude:session 1|session2|session 3" # # 07 Aug, 2020 # - Initial Revision # # Shows how to get a collection of all existing sessions # as session paths and modify the hostname and port for # all sessions using arguments specified when running # SecureCRT with the /Script command line argument along # with /ARG values for hostname and port. For example: # # SecureCRT.exe /Script C:/Users/user/Documents/ChangeHostnameAndPortForAllSessions.py /ARG hostname:192.168.232.220 /ARG port:2922 # # The above example will change the hostname and port for # *ALL* existing saved sessions in SecureCRT to match the # specified hostname and port. Only will work for SSH2 # sessions. Script modification will need to be made by # anyone who desires otherwise. # # An optional argument is supported: exclude # If present, the subsequent list of | separated # session names is excluded from any modification. # For example: # SecureCRT.exe /Script ChangeHostnameAndPortForAllSessions.py /ARG hostname:myhost port:2222 exclude:"This Session|And This One, Too" import os import re import time g_strLastError = "" g_strNewHostname = "" g_nNewPort = 0 g_cExcludeList = [] #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def ValidateArgs(): global g_strNewHostname, g_nNewPort, g_cExcludeList if crt.Arguments.Count < 1: crt.Dialog.MessageBox("Script arguments required. See script code comments for usage.") return False import re for strArgSpec in crt.Arguments: objMatch = re.match(r'(hostname|port|exclude)\:([^\s]+)', strArgSpec.lower()) if not objMatch: crt.Dialog.MessageBox( "Invalid argument provided.\r\n\r\n" + "Expected the following two arguments:\r\n\r\n" + "\thostname:new-host-spec-here\r\n" + "\tport:new-port-here" + "\r\n\r\n" + "For example:\r\n" + "\t/ARG hostame:192.168.232.220 /ARG port:2922") return False strOption = objMatch.group(1) strValue = objMatch.group(2) if strOption.lower() == "hostname": if IsValidHostname(strValue): g_strNewHostname = strValue else: crt.Dialog.MessageBox( "Invalid host argument provided: {}.\r\n\r\n".format(strValue) + "Expected the following two arguments:\r\n\r\n" + "\thostname:new-host-spec-here\r\n" + "\tport:new-port-here" + "\r\n\r\n" + "For example:\r\n" + "\t/ARG hostame:192.168.232.220 /ARG port:2922") return False elif strOption.lower() == "port": try: g_nNewPort = int(strValue) except: crt.Dialog.MessageBox( "Invalid port argument provided: {}.\r\n\r\n".format(strValue) + "Expected the following two arguments:\r\n\r\n" + "\thostname:new-host-spec-here\r\n" + "\tport:new-port-here" + "\r\n\r\n" + "For example:\r\n" + "\t/ARG hostame:192.168.232.220 /ARG port:2922") return False elif strOption.lower() == "exclude": # Create a list of specified session names to exclude, each # name separated by a "|" character. strArgValue = strArgSpec.replace("exclude:", "") g_cExcludeList = [s.strip() for s in strArgValue.split("|") if s <> ''] else: crt.Dialog.MessageBox( "Invalid argument provided.\r\n\r\n" + "Expected the following two arguments:\r\n\r\n" + "\thostname:new-host-spec-here\r\n" + "\tport:new-port-here" + "\r\n\r\n" + "For example:\r\n" + "\t/ARG hostame:192.168.232.220 /ARG port:2922") return False # No errors detected, and all arguments accounted for return True #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def IsValidHostname(strHostname): # If longer than 255, it's not a valid host name, IP addr, or FQDN if len(strHostname) > 255: return False # Just the same, if the length of strHostname is < 1, it's not legit. if len(strHostname) < 1: return False # remove trailing '.' char, if present (allowed, but not used) if strHostname[-1] == ".": strHostname = strHostname[:-1] objRegExp = re.compile("(?!-)[A-Z\d-]{1,63}(? 0: strExclusions = "\r\n\r\nExcluding:\n - {}".format("\n - ".join(g_cExcludeList)) else: strExclusions = "" strMsg = ("Apply the following host+port settings to all sessions?\r\n\r\n" + "New Hostname:\t{}\r\nNew Port:\t{}{}".format( g_strNewHostname, g_nNewPort, strExclusions)) if not crt.Dialog.MessageBox(strMsg, "Continue?", 4) == 6: return g_nStartTime = time.time() # Do something with the list of sessions we have nSessionsModified = 0 nSessionsSkipped = 0 nCurSession = 0 strStatus = "Checking sessions..." crt.Session.SetStatusText(strStatus) for strSessionPath in cSessionsList.keys(): nCurSession += 1 # Load current session's config objConfig = crt.OpenSessionConfiguration(strSessionPath) # Get the protocol name: strProtocol = objConfig.GetOption("Protocol Name") if strProtocol == "SSH2": bModified = False strHostname = objConfig.GetOption("Hostname") nPort = objConfig.GetOption("[SSH2] Port") if not strHostname == g_strNewHostname: objConfig.SetOption("Hostname", g_strNewHostname) bModified = True if not nPort == g_nNewPort: objConfig.SetOption("[SSH2] Port", g_nNewPort) bModified = True if bModified: objConfig.Save() bDisplayProgress = False # Optimize status bar displays to reduce overall time if nCurSession <= 100: bDisplayProgress = True elif nCurSession % 10 == 0: bDisplayProgress = True if bDisplayProgress: crt.Session.SetStatusText("({}/{}) - Updated {}".format( nCurSession, len(cSessionsList), os.path.basename(strSessionPath))) nSessionsModified += 1 else: nSessionsSkipped += 1 else: nSessionsSkipped += 1 nSecondsElapsed = round((time.time() - g_nStartTime) + nCollectionSecondsElapsed, 2) strReport = "Updated {} sessions in {} secs. ({} skipped)".format( nSessionsModified, nSecondsElapsed, nSessionsSkipped) crt.Session.SetStatusText(strReport) strMsg = strReport if nSessionsModified > 0: strMsg += "\n\nYou must close and re-open the Session Manager to see changes reflected." crt.Dialog.MessageBox(strMsg) crt.Sleep(2000) crt.Session.SetStatusText("") #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def GetListOfAllExistingSessions(): global g_cExcludeList # Get SecureCRT's configuration folder path g_strConfigFolder = GetConfigPath() # Get the Sessions folder path (may have %VARS% in it, so resolve them) # bgagnon: 08-09-2019, 9:08am : ?? env var? g_shell.ExpandEnvironmentStrings g_strSessionFolder = os.path.abspath(g_strConfigFolder) + "/Sessions/" # Create a dictionary in which results will be stored. # Key: session path (as seen in Session Manager w/in SecureCRT) # Value: file system path to .ini file cSessionsList = {} # These for loops "walk" through the config folder (Sessions) subfolders and files for root, dirs, files in os.walk(g_strSessionFolder): for name in files: vFilenameTokens = os.path.splitext(name) strFileBasename = vFilenameTokens[0] strFileExtension = vFilenameTokens[1].lower() if (strFileExtension == ".ini" and strFileBasename != "__FolderData__" and strFileBasename != "Default" and (not strFileBasename in g_cExcludeList) ): strFileSystemPath = os.path.join(root, name) strSessionMgrPath = strFileSystemPath.replace(g_strSessionFolder, "") strSessionMgrPath = strSessionMgrPath.replace(".ini", "") cSessionsList[strSessionMgrPath] = strFileSystemPath # Return the dictionary as the result of this function return cSessionsList #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def GetConfigPath(): objConfig = crt.OpenSessionConfiguration("Default") # Try to determine 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.replace('\\', '/') Main()