📜 ⬆️ ⬇️

Managing the list of 1C 8.2 databases using Active Directory

Greetings to you, dear reader!
By tradition, I ask you not to kick too much, because This is my first post.

So, about half a year ago, there was a task to automate the management of the list of 1C databases (of which more than 20 pieces have already divorced) from domain users.
This was done not only for the sake of convenience, but also in the framework of the project on the implementation of the “role-based access model”. In short, the meaning of this model is that each user in a domain is a member of a certain group (referred to as a post), which has a predefined set of privileges, including a list of information databases.

Since we have an Active Directory domain, it is logical to use group policies to perform our task.
Googling produced quite a lot of implementations (and even paid ones), but all of them, most often, boiled down to pre-formed files with database lists (ibases.v8i). We also wanted:
a) Centrally manage information connection settings (we have a client-server version with SQL databases).
b) Centrally manage the list of information databases accessible to the user, according to his “role”.
')
As a result, I will talk about a solution that has been working for more than six months in our company.


So let's get started.

Step 1 .

1C 8.2 stores the list of information bases in the ibases.v8i file, such a file is present in the profile for each user. The format and principle of this file is perfectly described here and here , so I do not see the point here to repeat it.
Also, in the same directory with the ibases.v8i file, the 1CEStart.cfg file is located, the peculiarity of this file is that it can prescribe the paths to individual * .v8i files containing connection parameters to specific information bases.
At startup, 1C takes the parameters of connections to the information databases from the files specified in 1CEStart.cfg and places them in ibases.v8i. We will use this feature.
First, we will create a v8i file for each information base.
The easiest way to create such a file is to right-click on the required database in the list, and select “Save link to file”:
image
However, it should be borne in mind that the v8i file thus generated contains some “extra” lines that we do not need. For normal operation, just leave the following:

[%NAME% ] Connect=Srvr="%server%";Ref="%base%"; ClientConnectionSpeed=Normal App=Auto WA=1 Version=8.2 

Further, it is necessary to place these files in a public place, for users of the local network, and to grant rights to "read". I did not bother, and just placed them in the NETLOGON folder of the domain controller. There are several reasons for this - this is both directory replication between domain controllers and fault tolerance (due to the fact that there are three controllers, and at any given time one of them is available).

Step 2 .

Once we are going to manage the list of infobases based on the user's belonging to this or that AD group, we will create in it the necessary number of security groups according to our 1C databases:
image

The prefix "1C_82" is mandatory, and further it will be clear why.

Now, in each newly created security group, in the “notes” field, we indicate the path to the corresponding v8i file:
image

On this with the groups finished.

Step 3 .

Create a group policy that will run the following vbs script each time the user logs in:

Vbs code
 On Error Resume Next Const PROPERTY_NOT_FOUND = &h8000500D Dim sGroupNames Dim sGroupDNs Dim aGroupNames Dim aGroupDNs Dim aMemof Dim oUser Dim tgdn Dim fso Dim V8iConfigFile Dim dir Const ForReading = 1, ForWriting = 2, ForAppending = 8 '   Set fso = CreateObject("Scripting.FileSystemObject") Set WshShell = WScript.CreateObject("Wscript.Shell") strSysVarTEMP = WshShell.ExpandEnvironmentStrings("%TEMP%") Set oScriptLog = fso.OpenTextFile(strSysVarTEMP + "\_dbconn.log",ForWriting,True) oScriptLog.Write "" strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "Start..." oScriptLog.WriteLine(strToLog) ',  1  Set objFSO = CreateObject("Scripting.FileSystemObject") If Not (objFSO.FolderExists("C:\Program Files\1cv82") Or objFSO.FolderExists("C:\Program Files (x86)\1cv82")) Then strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "1C 8.2 not installed... Quit..." oScriptLog.WriteLine(strToLog) WScript.quit End If '         ' APPDATA = WshShell.ExpandEnvironmentStrings("%APPDATA%") v8i = APPDATA + "\1C\1CEStart\ibases.v8i" If fso.FileExists(v8i) Then fso.DeleteFile(v8i) Set V8iConfigFile = fso.CreateTextFile(v8i ,True) strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "  v8i   " oScriptLog.WriteLine(strToLog) '    (1  ),       Else Set dir = fso.CreateFolder(APPDATA + "\1C") Set dir = fso.CreateFolder(dir + "\1CEStart") Set V8iConfigFile = fso.CreateTextFile(v8i ,True) strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "  v8i" oScriptLog.WriteLine(strToLog) End if ' ' Initialise strings. We make the assumption that every account is a member of two system groups ' sGroupNames = "Authenticated Users(S),Everyone(S)" ' ' Enter the DN for the user account here Set objSysInfo = CreateObject("ADSystemInfo") strUserName = objSysInfo.UserName strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "Logged user DN: "+strUserName oScriptLog.WriteLine(strToLog) '     Set oUser = GetObject("LDAP://" + strUserName) If Err.Number <> 0 Then strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "There is an error retrieving the account. Please check your distinguished name syntax assigned to the oUser object." oScriptLog.WriteLine(strToLog) WScript.quit End If ' ' Determine the DN of the primary group ' We make an assumption that every user account is a member of a primary group ' iPgid = oUser.Get("primaryGroupID") sGroupDNs = primgroup(iPgid) tgdn = sGroupDNs ' ' Call a subroutine to extract the group name and scope ' Add the result to the accumulated group name String ' Call Getmemof(tgdn) ' ' Check the direct group membership for the User account ' aMemOf = oUser.GetEx("memberOf") If Err.Number <> PROPERTY_NOT_FOUND Then ' ' Call a recursive subroutine to retrieve all indirect group memberships ' Err.clear For Each GroupDN in aMemof Call AddGroups(GroupDN) Call Getmemof(GroupDN) Next End If aGroupNames = Split(sGroupNames,",") aGroupDNs = Split(sGroupDNs,":") '  ,    1C_82 For Each strGroupDN in aGroupDNs if StrComp(Mid(strGroupDN,1,8), "CN=1C_82", vbTextCompare) = 0 Then strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "User is member of: " + strGroupDN oScriptLog.WriteLine(strToLog) Set objGroup = GetObject("LDAP://" & strGroupDN) If Err.Number <> 0 Then strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "There is an error retrieving the group. Please check your distinguished name syntax assigned to the objGroup object: " + strGroupDN oScriptLog.WriteLine(strToLog) WScript.quit End If strInfo = objGroup.Get("info") strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "Group " + strGroupDN +" info field: " + strInfo oScriptLog.WriteLine(strToLog) strAllInfo = strAllInfo & ":" & strInfo End If Next aInfoStrings = Split(strAllInfo,":") Call WriteDBSettings() Sub WriteDBSettings() '   v8i   1CEStart.cfg strSysVarAPPDATA = WshShell.ExpandEnvironmentStrings("%APPDATA%") strDBConfigFilePath = strSysVarAPPDATA + "\1C\1CEStart\1CEStart.cfg" strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "1C Config file is: " + strDBConfigFilePath oScriptLog.WriteLine(strToLog) If (fso.FileExists(strDBConfigFilePath)) Then Set objDBConfigFile = fso.OpenTextFile(strDBConfigFilePath,ForWriting,True) objDBConfigFile.Write "" For each strInfo in aInfoStrings objDBConfigFile.WriteLine("CommonInfoBases=" + strInfo) strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "Add Line: " + "CommonInfoBases=" + strInfo oScriptLog.WriteLine(strToLog) next '  0,      objDBConfigFile.WriteLine("UseHWLicenses=1") strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "Add Line: " + "UseHWLicenses=1" oScriptLog.WriteLine(strToLog) strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "Ready" oScriptLog.WriteLine(strToLog) objDBConfigFile.Close Else Set fso = CreateObject("Scripting.FileSystemObject") Set WshShell = WScript.CreateObject("Wscript.Shell") Set objDBConfigFile = fso.OpenTextFile(strDBConfigFilePath,ForWriting,True) objDBConfigFile.Write "" For each strInfo in aInfoStrings objDBConfigFile.WriteLine("CommonInfoBases=" + strInfo) strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "Add Line: " + "CommonInfoBases=" + strInfo oScriptLog.WriteLine(strToLog) next strToLog = CStr(Date())+" "+CStr(Time()) + " - " + "1C Config file" + strDBConfigFilePath + " Not Exist! Create!" oScriptLog.WriteLine(strToLog) WScript.Quit End If End Sub '************************************************************************************************* ' End of mainline code '************************************************************************************************* Function primgroup(groupid) ' This function accepts a primary group id ' It binds to the local domain and returns the DN of the primary group ' David Zemdegs 6 May 2008 ' Dim oRootDSE,oConn,oCmd,oRset Dim ADDomain,srchdmn ' Bind to loca domain Set oRootDSE = GetObject("LDAP://RootDSE") ADDomain = oRootDSE.Get("defaultNamingContext") srchdmn = "<LDAP://" & ADDomain & ">" ' ' Initialise AD search and obtain the recordset of groups ' Set oConn = CreateObject("ADODB.Connection") oConn.Open "Provider=ADsDSOObject;" Set oCmd = CreateObject("ADODB.Command") oCmd.ActiveConnection = oConn oCmd.CommandText = srchdmn & ";(objectCategory=Group);" & _ "distinguishedName,primaryGroupToken;subtree" Set oRset = oCmd.Execute ' ' Loop through the recordset and find the matching primary group token ' When found retrieve the DN and exit the loop ' Do Until oRset.EOF If oRset.Fields("primaryGroupToken") = groupid Then primgroup = oRset.Fields("distinguishedName") Exit Do End If oRset.MoveNext Loop ' ' Close and tidy up objects ' oConn.Close Set oRootDSE = Nothing Set oConn = Nothing Set oCmd = Nothing Set oRset = Nothing End Function Sub Getmemof(sDN) ' ' This is recursive subroutine that calls itself for memberof Property ' David Zemdegs 6 May 2008 ' On Error Resume Next Dim oGrp Dim aGrpMemOf Dim sGrpDN Set oGrp = GetObject("LDAP://" & sDN) aGrpMemOf = oGrp.GetEx("memberOf") If Err.Number <> PROPERTY_NOT_FOUND Then ' ' Call a recursive subroutine to retrieve all indirect group memberships ' Err.clear For Each sGrpDN in aGrpMemOf Call AddGroups(sGrpDN) Call Getmemof(sGrpDN) Next End If Err.clear Set oGrp = Nothing End Sub Sub AddGroups(sGdn) ' ' This subroutine accepts a disguished name ' It extracts the RDN as the group name and determines the group scope ' This is then appended to the group name String ' It also appends the DN to the DN String ' Const SCOPE_GLOBAL = &h2 Const SCOPE_LOCAL = &h4 Const SCOPE_UNIVERSAL = &h8 Dim SNewgrp ' ' Retrieve the group name ' iComma = InStr(1,sGdn,",") sGrpName = Mid(sGdn,4,iComma-4) ' ' Add the results to the group name String ' Check that the group doesnt already exist in the list ' sNewgrp = sGrpName If InStr(1,sGroupNames,SNewgrp,1) = 0 Then sGroupNames = sGroupNames & "," & SNewgrp End If ' ' Add the Groups DN to the string if not duplicate ' If InStr(1,sGroupDNs,sGdn,1) = 0 Then sGroupDNs = sGroupDNs & ":" & sGdn End If End Sub 


The logic of the script is as follows:
1. Checks if 1C is installed, if not - the script ends.
2. Checks if the ibases.v8i file exists, and overwrites it with a blank (or creates it in the absence).
3. Retrieves all groups from AD of which the user is a member.
4. Drops everything except those starting with 1C_82.
5. Gets the value of the attribute "Notes".
6. Writes the value of this attribute to the 1CEStart.cfg file
Along the way, a log is written:
For Windows 7 - C: \ Users \ username \ appdata \ Local \ Temp \ _dbconn.log
For Windows XP - C: \ Documents and Settings \ username \ Local Settings \ Temp \ _dbconn.log

Step 4 .

"We hang up" group policy on necessary OU or all domain. It is worth noting that in order for the script not to be used by everyone indiscriminately (not all users work with 1C), I added only the groups that we created in step 2 to the group policy security filter, so the script will only work for the users included in at least one of these groups:
image

Step 5 .

We include the group (read the position) of the user in those 1C groups that are provided by the role-based access model (although it is possible to take a single user - there are exceptions). After the reboot, the user will have an individual list of information databases for him.
Well, that seems to be all.
By the way, to apply the changes, the user does not have to relogin, you just need to force the user to execute this script in any convenient way, for example, by sending the script via email.

Thank you for your attention, I will be very happy if the article helps someone.

Source: https://habr.com/ru/post/231119/


All Articles