#$language = "Python" #$interface = "1.0" # IterateOverAllSessionRecursively_changeOptionValue.py # # This script is intended to change the hostname, since almost every other # Session Option can be changed via Default Session and Multiple Session methods # as documented in these tips on our website (to the best of our knowledge): # # https://www.vandyke.com/support/tips/defaultset.html # https://www.vandyke.com/support/tips/multisessions.html # # To be added to the feature request to add the ability to edit Hostname via # Default Session, please use the following feature request form: # # https://www.vandyke.com/cgi-bin/customer_form.php?cft=feature # # Description: # # Shows how to read data from sessions and change a value via # the SecureCRT SessionConfiguration object and functions. # # This script must be run from within SecureCRT. import os import sys import shutil import datetime import time from array import array MsgBox = crt.Dialog.MessageBox global g_nModSessCount global g_nSkipSessCount global g_nErrCount global g_nSessionCount g_nModSessCount = 0 g_nSkipSessCount = 0 g_nErrCount = 0 g_nSessionCount = 0 global g_cSessionsModified global g_cSessionsSkipped global g_cErrorsEncountered g_cSessionsModified = {} g_cSessionsSkipped = {} g_cErrorsEncountered = {} global g_bDisplaySetOptionErrors global g_strReply g_bDisplaySetOptionErrors = True g_strReply = "bail" #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def IsSessionReadOnly(strSessionPath): objConfig = crt.OpenSessionConfiguration(strSessionPath) strOptionName = "Upload Directory V2" strOrigValue = objConfig.GetOption(strOptionName) strTimeStamp = time.time() strDateTime = datetime.datetime.fromtimestamp(strTimeStamp).strftime('%Y%m%d_%H%M%S.%f')[:-3] objConfig.SetOption(strOptionName, strDateTime) objConfig.Save() objConfig = crt.OpenSessionConfiguration(strSessionPath) strNewValue = objConfig.GetOption(strOptionName) # Now, let's restore the setting to its original value objConfig.SetOption(strOptionName, strOrigValue) objConfig.Save() if strNewValue <> strDateTime: return True else: return False #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def WriteToFile(strText, strFilePath): try: strFile = open(strFilePath,"a") except Exception as strError: MsgBox("Could not open log file with error: " + str(strError) + "\r\rNot capturing log file.") return 0 if strText != "": strFile.write(strText) strFile.close return 1 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def GetDocumentsFolder(): # Same comments as above function (GetConfigPath()) 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("\\", "/") #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def DoWorkWithSession(strSession): global g_strOptionName, g_strSessionFolder global g_strCurrValue, g_strNewValue global g_strSummary, g_nSessionCount, g_nErrCount, g_nModSessCount global g_nSkipSessCount, g_cErrorsEncountered, g_cSessionsSkipped, g_cSessionsModified global g_strReply, g_bDisplaySetOptionErrors strSession = strSession.replace(".ini", "") crt.Session.SetStatusText("Checking: " + strSession) objSessionConfig = crt.OpenSessionConfiguration(strSession) # Get the specific data from session ini file # For example, # you would see the following in a .ini file for an SSH2 session: # S:"Protocol Name"=SSH2 # S:"Hostname"=192.168.0.1 try: strCurrValue = objSessionConfig.GetOption(g_strOptionName) except Exception as objInst: g_cErrorsEncountered[strSession] = \ "For session: " + strSession + " (get):\r\n" + \ "Error getting option '" + g_strOptionName + " ==> " + crt.GetLastErrorMessage() g_nErrCount += 1 return # Check user supplied value if g_strCurrValue == "[ALL_SESSIONS]" or strCurrValue.lower() == g_strCurrValue.lower(): crt.Session.SetStatusText("Modifying: " + strSession) try: objSessionConfig.SetOption(g_strOptionName, g_strNewValue) g_bDisplaySetOptionErrors = False except Exception as objInst: g_cErrorsEncountered[strSession] = \ "For session: " + strSession + " (set):\r\n" + \ "Error setting option '" + g_strOptionName + " ==> " + crt.GetLastErrorMessage() g_nErrCount += 1 g_bDisplaySetOptionErrors = True # Prompt user regarding how to handle SetOption errors if g_bDisplaySetOptionErrors: while True: g_strReply = crt.Dialog.Prompt("Error attempting to set value for option '" + g_strOptionName + "' for session '" + strSession + "'.\r\n\r\n" + "Should the script:\r\n" + "\t--> bail\tnow (cancel)\r\n" + "\t--> ignore\tthis error\r\n" + " \t-> ignore all\tfuture errors?", "Error", g_strReply) if g_strReply.lower() == "bail" or g_strReply == "": crt.Screen.SendSpecial("MENU_SCRIPT_CANCEL") return elif g_strReply.lower() == "ignore": break elif g_strReply.lower() in ["ia", "ignore all", "ignoreall", "ignore-all", "ignore all"]: g_bDisplaySetOptionErrors = False break else: MsgBox("Unrecognized response. Please enter one of:\r\n" + "\r\n" + "\tbail\r\n" + "\tignore\r\n" + "\tignore all", "Invalid option") # If reached here, save session changes, increment session count objSessionConfig.Save() g_nSessionCount += 1 # If no errors, add info to Sessions Modified dictionary if g_nErrCount == 0: g_cSessionsModified[strSession] = \ "Modified option '" + g_strOptionName + \ "' for session '" + strSession + \ "' from: '" + str(strCurrValue) + \ "' to: " + str(g_strNewValue) g_nModSessCount += 1 else: # If there were errors, add info to Errors Encountered dictionary g_cErrorsEncountered[strSession] = \ "Error modifying option '" + g_strOptionName \ + "' for session '" + strSession + \ "' from: '" + str(strCurrValue) + \ "' to: " + str(g_strNewValue) + \ "\r\n --> " + str(crt.GetLastErrorMessage()) g_nErrCount += 1 else: # Add info to Sessions Skipped dictionary crt.Session.SetStatusText("Skipping: " + strSession) g_cSessionsSkipped[strSession] = \ "Skipping session '" + strSession + \ "' because its '" + g_strOptionName + \ "' value isn't '" + str(g_strCurrValue) + "'." g_nSkipSessCount += 1 crt.Session.SetStatusText("") #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def Continue(strMsg): if crt.Dialog.MessageBox(strMsg, "Continue?", BUTTON_YESNO) != IDYES: return False else: return True g_strMyDocs = GetDocumentsFolder() g_strLogFile = os.path.join(g_strMyDocs, "##SessionIteratorLogFile.txt") # If the log file exists ... if os.path.isfile(g_strLogFile): # And there already is a backup file ... if os.path.isfile(g_strLogFile + ".bak"): # Delete it ... os.remove(g_strLogFile + ".bak") # now copy existing log file to become the backup file try: shutil.copy2(g_strLogFile, g_strLogFile + ".bak") except Exception as objInst: crt.Dialog.MessageBox( "Failed to copy file...\r\n" + "from: {0}\r\n\r\nto: {1}\r\n\r\nError:\r\n{2}".format( g_strLogFile, g_strLogFile + ".bak", str(objInst))) # Now delete existing one so we can write the latest one os.remove(g_strLogFile) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def Main(): global g_strOptionName, g_strSessionFolder global g_strCurrValue, g_strNewValue global g_strSummary, g_cErrorsEncountered, g_nErrCount global g_strLogFile, g_strSummary, g_nSessionCount, g_nModSessCount, g_nSkipSessCount # Check that sessions are not read-only if IsSessionReadOnly("Default"): g_cErrorsEncountered[strSession] = \ "For Default session (open):\r\n" + \ "Error accessing session due to config being read-only." g_nErrCount += 1 return # Get SecureCRT config path g_strConfigFolder = GetConfigPath() # Get the sessions folder g_strSessionFolder = os.path.join(g_strConfigFolder, "Sessions") + os.sep # Below are various dialogs prompting user for info on what option to change # and which sessions will be affected # Note that option name is the portion of "S:", "D:", etc. entries in the # session .ini file that are enclosed in quotes. # For example: Protocol Name, Hostname, etc. # S:"Protocol Name"=SSH2 # S:"Hostname"=127.0.0.1 g_strOptionName = "Hostname" g_strOptionName = crt.Dialog.Prompt("What is the .ini file option name you wish to modify?", "Specify Option Name", g_strOptionName) if g_strOptionName == "": return # Note that the current value is the portion of "S:", "D:", etc. entries in the # session .ini file that are on the right side of the "equal" (=) sign. # For example: SSH2, 127.0.0.1, etc. # S:"Protocol Name"=SSH2 # S:"Hostname"=127.0.0.1 g_strCurrValue = crt.Dialog.Prompt( "Changes can be made to all sessions " + "or **only** those sessions where the '" + g_strOptionName + "' matches the following value you supply.\r\n\r\n" + "To make the change to all sessions, enter ""[ALL_SESSIONS]"" below.\r\n\r\n" + "To change only the sessions where the current '" + g_strOptionName + "' value is empty, enter ""[EMPTY_VALUE]"" below.", "Specify Subset of Sessions", "[ALL_SESSIONS]") if g_strCurrValue == "": return if g_strCurrValue == "[EMPTY_VALUE]": g_strCurrValue = "" g_strNewValue = "" g_strNewValue = crt.Dialog.Prompt( "Please specify the new value for the option '" + g_strOptionName + "'.\r\n\r\n" + "If you wish to clear a value, specify ""[CLEAR_VALUE]"" below.", "Specify New Value", g_strNewValue) # Python needs T/F answers integer-ized? if g_strNewValue == "True": g_strNewValue = int(True) if g_strNewValue == "False": g_strNewValue = int(False) if g_strNewValue == "": return if g_strNewValue == "[CLEAR_VALUE]": g_strNewValue = "" # Get a timer going so that we can calculate how long it takes to # iterate over the sessions. nStartTime = time.time() # 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": strFileSystemPath = os.path.join(root, name) strSessionMgrPath = strFileSystemPath.replace(g_strSessionFolder, "") DoWorkWithSession(strSessionMgrPath) # Preparing reports for log and display in "Summary" strModifiedReport = "" if g_nModSessCount > 0: for strSessionPath in g_cSessionsModified.keys(): strLineToReport = str(g_cSessionsModified[strSessionPath]) if strModifiedReport == "": strModifiedReport = strLineToReport else: strModifiedReport = strModifiedReport + "\r\n" + strLineToReport strSkippedReport = "" if g_nSkipSessCount > 0: for strSessionPath in g_cSessionsSkipped.keys(): strLineToReport = str(g_cSessionsSkipped[strSessionPath]) if strSkippedReport == "": strSkippedReport = strLineToReport else: strSkippedReport = strSkippedReport + "\r\n" + strLineToReport strErrorReport = "" if g_nErrCount > 0: for strSessionPath in g_cErrorsEncountered.keys(): strLineToReport = str(g_cErrorsEncountered[strSessionPath]) if strErrorReport == "": strErrorReport = strLineToReport else: strErrorReport = strErrorReport + "\r\n" + strLineToReport # Summary to be displayed to user g_strSummary = ( "\r\n\r\nProcessed " + str(g_nSessionCount) + " sessions." + "\r\n\r\n" + "Sessions modified: " + str(g_nModSessCount) + "\r\n" + "-----------------------------------------------------------------------" + "\r\n" + strModifiedReport + "\r\n\r\n" + "Errors encountered: " + str(g_nErrCount) + "\r\n" + "-----------------------------------------------------------------------" + "\r\n" + strErrorReport + "\r\n\r\n" + "Sessions skipped: " + str(g_nSkipSessCount) + "\r\n" + "-----------------------------------------------------------------------" + "\r\n" + strSkippedReport) # Write to log file WriteToFile(g_strSummary, g_strLogFile) MsgBox(g_strSummary) nTimeElapsed = time.time() - nStartTime strResults = "Script completed in %2.3f seconds." % (nTimeElapsed) # Additions to summary to be displayed to user strMsg = ( strResults + "\r\n" + "\r\n" + " " + str(g_nModSessCount) + " sessions were modified." + "\r\n" + " " + str(g_nErrCount) + " errors were encountered." + "\r\n" + " " + str(g_nSkipSessCount) + " sessions were skipped (not targeted option value)") crt.Session.SetStatusText(strMsg) # Display summary to user crt.Dialog.MessageBox(strMsg) crt.Session.SetStatusText("") Main()