Technical Article

Distribution of Enterprise Manager registrations

,

This was just an answer in a forum in September, but I keep getting requests for the script. So I am sharing it here for anyone that could be interested:

Problem: large amount of registered servers, multiple DBA's needing updated registration info, DBA workstations added or rebuilt, many servers added at once. In cases like these, manually rebuilding or updating the registration info is not nice ... 😉

With SQL7/NT4 we could save the registrations with a registry save/restore, but this doesn't work on SQL2K/W2K anymore. When trying the "Read from remote" option from EM, we found it was also not working (Q280836).

Using this DMO script we can solve it:

a) Run it on the "source" workstation with CSCRIPT //NOLOGO, it shows all the current registrations. Redirecting the output we create the configuration file.

b) We could make changes to this config file with Notepad, for example regrouping servers, or adding servers that are still not available.

c) Running the script on the "destination" machine with this config file as a parameter rebuilds the whole registration info according to the definitions.

Before this it drops all current EM configurations for your account (HKCU) and also any non-"user independent" EM registration (HKLM) (this is on purpose in order not to leave unsafe shared configurations laying around). As a safety measure, previously existing registration definitions are shown before being deleted.

Interesting side-note: standard security passwords are exposed by DMO without any restriction if you have access to the DBA workstation. Makes another good point for not using standard security. But if unavoidable, at least always use the "user independent" registration option ..., from another login you will not get access to them.

The script comments restrictions about special characters in server names, passwords and group names. Another disadvantage: it cannot handle "

'************************************************************************
'*     SCRIPT TO SHOW SQL ENTERPRISE MANAGER REGISTRATION INFO AND      *
'*     TO REBUILD REGISTRATION INFO BASED ON A CONFIGURATION FILE       *
'*     THAT CAN BE THE CAPTURED FROM THE OUTPUT OF THIS SCRIPT          *
'*                                                                      *
'*     Gustavo Merle - 08-Aug-2003                                      *
'************************************************************************


'????????????????????????????????????????????????????????????????????????
'
' *** WARNING ****
'
' Enterprise Manager can store SQL Server registration information in
' HKLM (available to every user connecting to the machine) or in HKCU
' (only for currently logged in user).
'
' When registering with standard security, the password is hidden in
' Enterprise Manager, and encrypted in the registry. BUT!!! WITH A
' VERY SIMPLE SQLDMO SCRIPT (as this script shows) THE PASSWORD CAN BE
' RETRIEVED IN CLEAR TEXT!!
'
' What this means is that when using the shared mode (HKLM) it is trivial
' for anyone logging in into the machine to retrieve the sa password
' (for example Asset Deployment, Domain Admins, etc). This is a high
' security risk.
'
' If a reason to use shared mode was to simplify the management of
' all the server registrations for different DBAs in different
' monitoring machines, the goal of this script is to simplify this
' process, but keeping the registration information in everyone's own
' profiles and not publicly available.
'
' *** WARNING ****
'
' The output created by this script contains SQL registration info,
' INCLUDING THE SA PASSWORD IN CLEARTEXT. Please always handle this
' output information (and also if possible this same script) very
' carefully (ZIP files with sa password encryption?) and delete any
' copies that could remain.
'
'????????????????????????????????????????????????????????????????????????


'========================================================================
'USAGE: When executed with CSCRIPT //NOLOGO without parameters, an output
'       is generated showing all groups and server registration info from
'       Enterprise Manager. If this output is captured to a file, it can
'       be used to later rebuild the same registration info on another
'       Enterprise Manager.
'       The output generated shows both the registrations for the current
'       profile (HKCU) and also "shared" registrations (HKLM).
'       If "blnShowProperties" is changed from False to True, additional
'       Properties information is shown.
'
'       When executed with a filename as parameter, the script REBUILDS
'       the registration information for Enterprise Manager based on the
'       information contained in the file.
'       1) It first wipes out the whole "shared" registrations.
'       2) Then it also wipes out the whole existing "user independent"
'          registrations.
'       3) Afterwards the groups and server registrations listed in the
'          configuration file are created (see notes below) in the
'          "user independent" (HKCU) mode.
'       4) The Enterprise Manager is left configured in the "user
'          independent" mode.
'        Any error breaks the execution of the script.
'
'        Just in case: backup following registry folders before applying
'        the changes:
'          HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\80\Tools\SQLEW
'          HKCU\Software\Microsoft\Microsoft SQL Server\80\Tools\SQLEW
'
'        See below the description of the configuration file format.
'========================================================================


'========================================================================
'WARNING: CLOSE ENTERPRISE MANAGER BEFORE EXECUTING THIS SCRIPT TO WRITE
'         REGISTRATION INFO, FOR THE CHANGES OF THIS SCRIPT NOT TO BE
'         OVERWRITTEN BY CHANGES IN ENTERPRISE MANAGER'S CACHE WHEN
'         CLOSING IT !!
'========================================================================


'------------------------------------------------------------------------
'NOTE 1: The option "Display SQL Server state in console", accessible via
'        Edit SQL Server Registration properties ... | General | Options
'        cannot be managed by this script. Registrations created by this
'        script will always have this option disabled... (Nikola, any
'        suggestions? ...) RegisteredServer.PersistFlags returns only 2
'        bits for the other 2 options ("show system objects" and "auto
'        restart"). I played setting more bits in PersistFlags when
'        registering, but the extra bits are ignored...
'------------------------------------------------------------------------

'------------------------------------------------------------------------
'NOTE 2: The Enterprise Manager Server Registration options include "Show
'        system databases and system objects" and "Automatically start
'        SQL Server when connecting". When this script is executed to
'        list the current registration information, these options are
'        shown as:
'
'          {__} :  no autostart, no sys
'          {_S} :  no autostart, sys *** PREFERRED MODE ***
'          {A_} :  autostart, no sys
'          {AS} :  autostart, sys *** default options when registering ***
'                                 *** via Enterprise Manager           ***
'
'        But when the script is executed to create the registrations, these
'        options are ignored, and the options {_S} are always set to show
'        all DBs and system objects, and to avoid accidentally starting a
'        SQL Server that was stopped on purpose (or a cluster that needs to
'        be handled via the Cluster Administrator!)
'------------------------------------------------------------------------

'------------------------------------------------------------------------
'NOTE 3: In SQL 2000 Enterprise Manager the option to read registration
'        information from a remote server does not work. This script
'        overrides this setting to always read it locally (even when
'        executed to only show registration information).
'------------------------------------------------------------------------

'------------------------------------------------------------------------
'WARNING: For simplicity, THIS SCRIPT DOES NOT HANDLE SPACES OR TABS IN
'         SERVER NAMES, USER NAMES OR PASSWORDS. Server names cannot
'         contain "[". Spaces are handled correctly only for Group names.
'         Group names cannot contain the "]" character. Blanks are also
'         not supported in account names and passwords.
'------------------------------------------------------------------------


'========================================================================
'CONFIGURATION FILE FORMAT:
'
' - Tab characters are interpreted as spaces
' - Blank lines are ignored
' - Leading spaces are only considered for group hierarchy, and ignored
'   for the rest of the lines
' - Lines beginning (after the leading spaces) with "--" are ignored
' - Groups are defined enclosed in []. A line is considered a group
'   definition only if the first character after the leading spaces is a
'   "[". Everything after the (first) closing "]" is ignored. If "]" is
'   missing, the whole line (after "[") is considered the group name.
' - Any line before the first group definition is ignored.
' - The first group definition gets level 1
' - Increasing indentation increases the group hierarchy level by 1
'
' - Decreasing indentation only lowers the new group's hierarchy when
'   reaching or crossing the n-1 level's group indentation
'   Example: ("." shown for spaces)  Creates:
'   --------                         --------
'   ..[GROUP1]      level 1          +- GROUP1
'   ......[GROUP2]  level 2          |  +- GROUP2
'   ...[GROUP3]     level 2          |  +- GROUP3
'   ....[GROUP4]    level 3          |     +- GROUP4
'   [GROUP5]        level 1          +- GROUP5
'
' - Server definition lines (one server per line) are applied to the
'   last defined group (indentation is ignored for server definitions)
' - Server definition lines consist of several fields separated by 1 or
'   more spaces:
'    a) 0 or more leading spaces (irrelevant)
'    b) servername (no spaces in name)
'    c) type of registration:
'         (t) trusted connection
'         (S) standard security
'         (P) standard security but prompting for password when
'             connecting
'    d) login (ignored for (t))
'    e) password (ignored for (t) and (P))
'    f) {__} | {A_} | {_S} | {AS} (see NOTE 2)
'       ignored during creation of registrations
'    g) any further field is also ignored
'========================================================================


'
'Registry location for Enterprise Manager user related registration Info:
'"HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\80\Tools\SQLEW\"

'Enterprise Manager - Tools - Options - General
'- Server registration information - Read from remote - Server Name:
'
'With "SQLDMO.Application":
'GroupRegistrationServer = '' local, 'XXX' remote server
'(with UseCurrentUserServerGroups False when server specified)
'
'From Registry:
'RegisteredServersSource REG_SZ '' local, 'XXX' remote server
'(with UserRegistrationInfo 0x0 when server specified)
'
'Remote Server source doesn't work in SQL 2000 so we set it to local
'

'Enterprise Manager - Tools - Options - General
'- Server registration information - Read/Store locally
'- Read/Store user independent
'
'With "SQLDMO.Application":
'UseCurrentUserServerGroups = True user indep, False shared
'
'From Registry:
'UserRegistrationInfo REG_DWORD 0x1 user indep, 0x0 shared
'
'Shared: uses LocalMachine, User Independent: uses CurrentUser
'

'Registry location for Enterprise Manager shared server registration Info:
'"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\80\Tools\SQLEW\"
'"Registered Servers X"\[EntMgrGroup]
'
'Registry location for Enterprise Manager user indep server registration Info:
'"HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\80\Tools\SQLEW\"
'"Registered Servers X"\[EntMgrGroup]
'



'...........................................................................
'Initialization:
'
option explicit

'DEBUG:
dim blnShowProperties
blnShowProperties = False 'show all properties of registration objects
                          'and details of registrations rebuild



'...........................................................................
'Parameters Handling:
'
dim intArgCount
intArgCount = WScript.Arguments.Count

dim strMsg
If intArgCount > 1 then
   strMsg = "Invalid Parameters: " + vbCrLf
   strMsg = strMsg + " - no parameters: create list"+ vbCrLf
   strMsg = strMsg + " - one parameter: config file to rebuild registrations"
   MsgBox strMsg
   WScript.Quit 1
End If

dim strFile, objFSO
If intArgCount = 1 then
   strFile = WScript.Arguments(0)
   Set objFSO = CreateObject("Scripting.FileSystemObject")
   If not objFSO.FileExists(strFile) then
      MsgBox "ERROR: File """& strFile & """ does not exist!"
      Set objFSO = nothing
      WScript.Quit 1
   End If
End If



'...........................................................................
'DMO Object to manage registrations (not server-bound):
'
dim objDMO
Set objDMO = CreateObject ("SQLDMO.Application")

'Remote Server source doesn't work in SQL 2000 so we set it to local here:
objDMO.GroupRegistrationServer = "" ' local



'...........................................................................
'LIST REGISTRATIONS
'This is the only section executed when no parameters are specified
'
If intArgCount = 0 then showRegistrations ""



'...........................................................................
'REBUILD REGISTRATIONS
'
'This section is only executed when a configuration file was specified
'as parameter.
'The wipe-out process of existing registrations is only started if at
'least one valid group definition was found in the configuration file.
'
If intArgCount = 1 then ' rebuild registrations

   'First show pre-existing registrations
   showRegistrations " INITIAL"

   'All pre-existing shared and user-independent registrations will be
   'deleted once we find a first valid group line in the configuration file

   'Tracking of group definitions. Ignore lines before first group
   dim blnGroupFound
   blnGroupFound = False
   'Dictionary object to track levels of groups
   dim objLevels
   Set objLevels = CreateObject("Scripting.Dictionary")
   'Track current level
   dim intCurrLevel
   intCurrLevel = 0
   'Object positioned in current group
   dim objCurrGroup
   Set objCurrGroup = objDMO ' initially in Application level

   'Output string initialization
   dim strList
   strList = "-- REGISTRATIONS BASED ON " & strFile & vbCrLf

   dim objFile, intLineNr, strLine
   Const ForReading = 1, CreateFalse = False
   Set objFile = objFSO.OpenTextFile(strFile, ForReading, CreateFalse)
   Do until objFile.AtEndOfStream
      intLineNr = objFile.Line ' positioned before next line to read
      strLine = Replace(objFile.ReadLine, vbTab, " ") ' tabs as spaces

      'GROUP LINE ----------------------------------------------------------------
      If fnIsGroup (strLine) then 'Group line

         If blnGroupFound = False then 'if it's the first group we find ...
            'Only after we find the first valid group we remove ALL existing
            'registrations. (Only root groups need to be removed, because the
            'Remove method deletes everything below  - subgroups and servers).

            dim objSubGroup

            '1st: delete all shared registrations:
            objDMO.UseCurrentUserServerGroups = False ' shared
            objDMO.ServerGroups.Refresh
            For each objSubGroup in objDMO.ServerGroups
               objSubGroup.Remove
            Next
            strList = strList & "--------------------------------------------" & vbCrLf
            strList = strList & "-- SHARED REGISTRATIONS DELETED !!" & vbCrLf

            '2nd: delete all 'user independent' registrations:
            objDMO.UseCurrentUserServerGroups = True ' user independent
            objDMO.ServerGroups.Refresh
            For each objSubGroup in objDMO.ServerGroups
               objSubGroup.Remove
            Next
            strList = strList & "--------------------------------------------" & vbCrLf
            strList = strList & "-- USER INDEPENDENT REGISTRATIONS DELETED !!" & vbCrLf
            strList = strList & "--------------------------------------------" & vbCrLf

            'set flag that we are already processing groups so we stop ignoring input lines
            'and do not delete the registrations again.
            blnGroupFound = True
         End If

         dim intIndent, strGroup
         getGroupInfo strLine, intIndent, strGroup

         dim intNewLevel
         'Obtain the level where the new group should belong to
         intNewLevel = newLevel(intIndent, objLevels, strGroup)

         'Position objCurrGroup to create the new group
         gotoLevel intNewLevel - 1, objCurrGroup, intCurrLevel, objLevels
         intCurrLevel = intNewLevel - 1

         'Try to create the group
         dim objNewGroup
         Set objNewGroup = CreateObject ("SQLDMO.ServerGroup")
         objNewGroup.Name = strGroup
         objCurrGroup.ServerGroups.Add objNewGroup
         Set objNewGroup = nothing

         'Everything OK, group created. Goto to the group
         Set objCurrGroup = objCurrGroup.ServerGroups.Item(strGroup)
         intCurrLevel = intNewLevel

         strList = strList & intLineNr & ": ** GROUP (L" & intNewLevel & "): """  & _
            strLine & """ created." & vbCrLf


      'IGNORED LINE --------------------------------------------------------------
      ElseIf not blnGroupFound or fnToIgnore (strLine) then 'Line to ignore
         'also ignore everything before first group
         strList = strList & intLineNr & ": -- IGNORED: """ & strLine & """" & vbCrLf


      'SERVER LINE ---------------------------------------------------------------
      ElseIf fnValidServer (strLine) then 'Server registr line
         dim strServer, strMode, strLogin, strPassword
         getServerInfo strLine, strServer, strMode, strLogin, strPassword

         'Create the new server registration:
         dim objNewRegisteredServer
         Set objNewRegisteredServer = CreateObject ("SQLDMO.RegisteredServer")
         objNewRegisteredServer.Name = strServer
         Select Case strMode
          case "(S)"   objNewRegisteredServer.UseTrustedConnection = 0
          case "(t)"   objNewRegisteredServer.UseTrustedConnection = 1
          case "(P)"   objNewRegisteredServer.UseTrustedConnection = 2
         End Select
         If strMode = "(S)" or strMode = "(P)" then
          objNewRegisteredServer.Login = strLogin
         End If
         If strMode = "(S)" then
          objNewRegisteredServer.Password = strPassword
         End If

         ' " {_S} " ' no autostart, system objects *** PREFERRED MODE ***
         objNewRegisteredServer.PersistFlags =  1

         'Add the server:
         objCurrGroup.RegisteredServers.Add objNewRegisteredServer

         'Cleanup:
         Set objNewRegisteredServer = nothing

         strList = strList & intLineNr & ": ## SERVER: """ & strLine & """ created." & vbCrLf


      'INVALID LINE --------------------------------------------------------------
      Else 'Invalid line
         strList = strList & intLineNr & ": ?? INVALID LINE IGNORED: """ & strLine & """" & vbCrLf
      End If

   Loop

   strList = strList & "-- END REGISTRATIONS CREATION" & vbCrLf & vbCrLf
   objFile.Close
   Set objFile = nothing
   Set objLevels = nothing
   Set objCurrGroup = nothing
   If blnShowProperties then WScript.Echo strList

   'show what remained from the registrations:
   showRegistrations " FINAL"

End If


'Cleanup
Set objDMO = nothing
If intArgCount = 1 then Set objFSO = nothing
WScript.Quit 0

'
' END OF SCRIPT - Start of auxiliary functions
'...........................................................................




'------------------------------------------------------------------------------------------
'Procedures to show existing registrations
'
Sub showRegistrations (strAux)
   dim strList, strPrefix, strTitle

   'First show (local) shared registrations:
   objDMO.UseCurrentUserServerGroups = False ' shared

   strTitle  = "-- ##" & strAux & " SHARED REGISTRATIONS ## -------------------"
   strList   = strTitle & vbCrLf
   strPrefix = "-- "
   listGroups objDMO, strList, strPrefix

   'Now show user independent registrations:
   objDMO.UseCurrentUserServerGroups = True ' user independent

   strTitle  = "-- ##" & strAux & " USER INDEPENDENT REGISTRATIONS ## ---------"
   strList   = strList & vbCrLf & strTitle & vbCrLf
   strPrefix = ""
   listGroups objDMO, strList, strPrefix

   'End
   strTitle  = "-- ## END" & strAux & " REGISTRATIONS ## ----------------------"
   strList   = strList & strTitle & vbCrLf

   WScript.Echo strList
End Sub



Sub listGroups (objRoot, strList, strPrefix)
   'show properties on top for the case we want to see properties
   'of SQLDMO.Application (root group):
   If blnShowProperties Then showProperties objRoot, strList, strPrefix

   ' show servers in this group
   listServersInGroup objRoot, strList, strPrefix

   'show subgroups
   dim objSubGroups, objSubGroup
   Set objSubGroups = objRoot.ServerGroups
   objSubGroups.Refresh
   For each objSubGroup in objSubGroups
      'show group name here and not on top in order not to show [Microsoft
      'SQL-DMO] for the root that is not an Enterprise Manager group:
      strList = strList & strPrefix & "[" & objSubGroup.Name & "]" & vbCrLf
      listGroups objSubGroup, strList, strPrefix & "  "
   Next
   Set objSubGroups = nothing
End Sub



Sub listServersInGroup (objRoot, strList, strPrefix)
   dim objRegisteredServers, objRegisteredServer
   On Error Resume Next
   Set objRegisteredServers = objRoot.RegisteredServers
   If err.number = 0 then ' root folder does not support servers, only groups
      On Error Goto 0
      objRegisteredServers.Refresh
      For each objRegisteredServer in objRegisteredServers
         showServerDetails objRegisteredServer, strList, strPrefix
      Next
   else
      On Error Goto 0
   End If
   Set objRegisteredServers = nothing
End Sub



Sub showServerDetails (objServer, strList, strPrefix)
   strList = strList & strPrefix & objServer.Name
   Select Case objServer.UseTrustedConnection
      case 0    strList = strList & " (S)" ' standard
      case 1    strList = strList & " (t)" ' trusted
      case 2    strList = strList & " (P)" ' standard with prompt
      case else strList = strList & " (?)" '
   End Select
   strList = strList & " " & objServer.Login
   strList = strList & " " & objServer.Password

   ' 0 PersistFlags
   '   Show system databases and system objects
   '   Automatically start SQL Server when connecting
   '
   ' 1 PersistFlags
   ' X Show system databases and system objects
   '   Automatically start SQL Server when connecting
   '
   ' 2 PersistFlags
   '   Show system databases and system objects
   ' X Automatically start SQL Server when connecting
   '
   ' 3 PersistFlags
   ' X Show system databases and system objects
   ' X Automatically start SQL Server when connecting
   '
   Select Case objServer.PersistFlags
      case 0    strList = strList & " {__} " ' no autostart, no sys
      case 1    strList = strList & " {_S} " ' no autostart, sys *** PREFERRED MODE ***
      case 2    strList = strList & " {A_} " ' autostart, no sys
      case 3    strList = strList & " {AS} " ' autostart, sys
      case else strList = strList & " {??} " '
   End Select

   strList = strList & vbCrLf

   If blnShowProperties Then
      showProperties objServer, strList, strPrefix
   End If
End Sub



Sub showProperties (obj, strList, strPrefix)
   dim oProp, Value
   For each oProp in obj.Properties
      strList = strList & strPrefix & " -- # " & oProp.Name
      Value = oProp.Value
      strList = strList & ": " & Value & vbCrLf
   Next
End Sub



'------------------------------------------------------------------------------------------
'Functions and procedures to parse configuration file for registrations creation
'
Function fnIsGroup (strLine)
   dim objRE
   Set objRE = new RegExp
   objRE.IgnoreCase = False
   objRE.Global = False
   objRE.MultiLine = False
   'ignore leading spaces, opening "[", at least one non-"]"
   objRE.pattern = "^ *\[[^\]]+"
   fnIsGroup = objRE.Test(strLine)
   Set objRE = nothing
End Function

Function fnToIgnore (strLine)
   dim objRE
   Set objRE = new RegExp
   objRE.IgnoreCase = False
   objRE.Global = False
   objRE.MultiLine = False
   'ignore blank lines or starting with -- after blanks
   objRE.pattern = "^ *(?:$|--)"
   fnToIgnore = objRE.Test(strLine)
   Set objRE = nothing
End Function

Function fnValidServer (strLine)
   dim objRE
   Set objRE = new RegExp
   objRE.IgnoreCase = True 'don't care if (t) or (T)
   objRE.Global = False
   objRE.MultiLine = False
   'registr trusted    SERVER (t)        |
   'registr std prompt SERVER (P) login  |
   'registr standard   SERVER (S) login password
   objRE.pattern = "^ *[^ ]+ +(?:\(t\)|\(P\) +[^ ]+|\(S\) +[^ ]+ +[^ ]+)"
   fnValidServer = objRE.Test(strLine)
   Set objRE = nothing
End Function



Sub getGroupInfo (byVal strLine, byRef intIndent, byRef strGroup)
   dim objRE
   intIndent = NULL
   strGroup = NULL

   Set objRE = new RegExp
   objRE.IgnoreCase = False
   objRE.Global = False
   objRE.MultiLine = False
   'leading spaces define group level
   'group name starts after [, until ] or EOL
   objRE.pattern = "^( *)\[([^\]]+)"
   dim objMatches
   Set objMatches = objRE.Execute(strLine)
   If objMatches.Count > 0 Then
      dim objMatch
      Set objMatch = objMatches(0) 'only the first one
      If objMatch.Submatches.Count > 0 Then
         intIndent = Len(objMatch.Submatches(0))
      End If
      If objMatch.Submatches.Count > 1 Then
         strGroup = objMatch.Submatches(1)
      End If
      Set objMatch = nothing
   End If
   Set objMatches = nothing
   Set objRE = nothing
End Sub



Sub getServerInfo (byVal strLine, byRef strServer, byRef strMode, byRef strLogin, byRef strPassword)
   dim objRE
   strServer = NULL
   strMode = NULL
   strLogin = NULL
   strPassword = NULL

   Set objRE = new RegExp
   objRE.IgnoreCase =  True 'don't care if (t) or (T)
   objRE.Global = False
   objRE.MultiLine = False
   'registr trusted    SERVER (t)        |
   'registr std prompt SERVER (P) login  |
   'registr standard   SERVER (S) login password
   objRE.pattern = "^ *([^ ]+) +(?:(\(t\))|(\(P\)) +([^ ]+)|(\(S\)) +([^ ]+) +([^ ]+))"
   'submatches         (  0  )  {  (  1  )|(  2  )  (  3  )|(  4  )  (  5  )  (  6  )}
   'this pattern returns always 7 submatches, and depending on the or condition
   'the rest of the submatches show up as empty
   dim objMatches
   Set objMatches = objRE.Execute(strLine)
   If objMatches.Count > 0 Then
      dim objMatch
      Set objMatch = objMatches(0) 'only the first one
      If objMatch.Submatches.Count > 0 Then
         strServer = UCase(objMatch.Submatches(0)) 'Server registration uppercase
      End If
      If objMatch.Submatches.Count > 1 and not IsEmpty(objMatch.Submatches(1)) Then
         strMode = "(t)"
      End If
      If objMatch.Submatches.Count > 2 and not IsEmpty(objMatch.Submatches(2)) Then
         strMode = "(P)"
      End If
      If objMatch.Submatches.Count > 3 and not IsEmpty(objMatch.Submatches(3)) Then
         strLogin = objMatch.Submatches(3)
      End If
      If objMatch.Submatches.Count > 4 and not IsEmpty(objMatch.Submatches(4)) Then
         strMode = "(S)"
      End If
      If objMatch.Submatches.Count > 5 and not IsEmpty(objMatch.Submatches(5)) Then
         strLogin = objMatch.Submatches(5)
      End If
      If objMatch.Submatches.Count > 6 and not IsEmpty(objMatch.Submatches(6)) Then
         strPassword = objMatch.Submatches(6)
      End If
      Set objMatch = nothing
   End If
   Set objMatches = nothing
   Set objRE = nothing
End Sub



'........................................................................................
' Levels of groups are defined by the indentation of the group name in the
' configuration file.
' The first group defined is level 1
' The "current level" is the level of the last group defined
' If a new group is defined:
' - If the indentation is higher than the indentation of the group that
'   defined the current level Ln, it gets level Ln+1
' - If the indentation is the same as the indentation of the group that
'   defined the current level Ln, it also gets level Ln
' - If the indentation is lower than the indentation of the group that
'   defined the current level Ln, the level it gets depends on the
'   indentation of the groups that defined the current "path" of levels:
'      Indentation (spaces)     Level
'     ----------------------   -------
'           S1                   L1     S1 >= 0
'           S2                   L2     S2 > S1
'           ...                  ...
'           Sn-2                 Ln-2
'           Sn-1                 Ln-1
'           Sn                   Ln     << Current level
'
'              Sn > Sn-1 > Sn-2
'
'      New group with Sx < Sn is level Ln   if Sn-1 < Sx <= Sn
'      New group with Sx < Sn is level Ln-1 if Sn-2 < Sx <= Sn-1
'      ....
'      New group with Sx < Sn is level L2   if S1   < Sx <= S2
'      New group with Sx < Sn is level L1   if 0   <= Sx <= S1
'
' A Dictionary object is used to track the the indentation levels
' only of the groups that define the path from the root to the current
' group. Key is the level and the value is the indentation (amount of
' spaces).


'The function receives the indentation of a new
'group definition and the group name, and returns
'the level this new group belongs to. The dictionary
'object tracks the path to the current group from
'the root, and the group name at each level
Function newLevel(intIndent, objLevels, strGroup)
   'normalize parameter
   If not IsNumeric(intIndent) or intIndent < 0 then
      newLevel = NULL
      exit Function
   End If
   'discard eventual fractional parts
   intIndent = Int(intIndent)

   'if first element ...
   If objLevels.count = 0 then
      objLevels.add 1, Array(intIndent, strGroup)
      newLevel = 1
      exit Function
   End If

   'if higher indentation as current ...
   If  intIndent > objLevels.Item(objLevels.count)(0) then
      objLevels.add (objLevels.count+1), Array(intIndent, strGroup)
      newLevel = objLevels.count
      exit Function
   End If

   'if same indentation as current ...
   If  intIndent = objLevels.Item(objLevels.count)(0) then
      'replace with new group name
      objLevels.Remove(objLevels.count)
      objLevels.add (objLevels.count+1), Array(intIndent, strGroup)
      newLevel = objLevels.count
      exit Function
   End If

   'if lower indentation as current ...
   If  intIndent < objLevels.Item(objLevels.count)(0) then
      'first remove current last level
      objLevels.Remove(objLevels.count)
      'and try again ...
      newLevel = newLevel(intIndent, objLevels, strGroup)
      exit Function
   End If
End Function


'------------------------------------------------------------------------------------------
'Functions and procedures to create groups and server registrations
'
Sub gotoLevel (byVal intDestLevel, byRef objCurrGroup, byVal intCurrLevel, byVal objLevels)
   'parent property not supported on newly created groups to back-track,
   'so we go up from the root level ...

   If intDestLevel = intCurrLevel then exit Sub
   If intDestLevel > intCurrLevel then
      'We can only go down, we should never get a request to go up...
      'Put the object in an invalid state to abort script
      Set objCurrGroup = nothing
      objCurrGroup = NULL
      exit Sub
   End If
   'From here we only have reuquests to go down
   If intCurrLevel <= 0 then
      'We cannot go down from level 0 (.. or less)  ...
      'Put the object in an invalid state to abort script
      Set objCurrGroup = nothing
      objCurrGroup = NULL
      exit Sub
   End If
   'Here we only have valid requests to descend one or more levels:
   'But we start from Level 0 going up up to intDestLevel
   Set objCurrGroup = objCurrGroup.Application
   intCurrLevel = 0
   While intCurrLevel < intDestLevel
      intCurrLevel = intCurrLevel + 1
      dim strCurrGroup
      strCurrGroup = objLevels.Item(intCurrLevel)(1)
      Set objCurrGroup = objCurrGroup.ServerGroups.Item(strCurrGroup)
   Wend
End Sub

Rate

5 (1)

You rated this post out of 5. Change rating

Share

Share

Rate

5 (1)

You rated this post out of 5. Change rating