
The continuation of "experienced trifles." Previous parts:
one ,
two ,
three ,
four .
In this post we will talk about groups in Active Directory. I will not go deep into the theory and talk about universal, global local groups - those who wish can find all the details in the documentation, since there is plenty of it. Let's talk about why groups are needed at all and what kind of “goodies” can be obtained with their help.
- Use groups wherever you can, instead of individual users. In ACLs, permissions, granting rights, group policy, etc. Even if there is only one person in the group now - it’s all the same, use groups. This not only speeds up the operation of the system (for example, ACLs from 2-3 groups and ACLs from 15 users are not processed at the same time), but in the future it will greatly simplify management. You do not need to remember where and how you assigned this or that right, you will have a single ActiveDirectory console in which you simply add a new person, or remove the old person from the group, that's all. Setup complete.
- Call the group meaningfully, write detailed information in the Description, use prefixes. For example, the groups that are used to allow access to folders can be called FLD_FolderName_RW , and the Internet access group I_FullAccess . The prefix allows you to quickly find groups in AD (click to add a user to a group , and the prefix immediately contains a list of exactly the groups you are looking for). A meaningful name and description in the Description will allow you (or not you) in six months \ year \ it.d. remember the meaning you put into the group you created.
- Do not get carried away nested groups. This is a useful thing, but if you overdo it, you can come to a cyclic nesting and confuse yourself.
- Delegate group management. Bring all your groups into a separate structured OU and delegate group membership management rights to those responsible. For example, we have delegated access control to folders to secretaries, and management of remote access permission is delegated to the Security Council. All the red tape on "write a service - sign it from the person in charge - ok, we added you - here's your instruction - a service to the archive" passed to them, and part of the routine went away from the IT department.
- Use groups creatively, for example, to assign any privileges, distribute printers, lay out shortcuts on desktops, prescribe 1C databases using logon scripts, etc. Given that a group in AD is a fairly “capacious” object, you can store various settings directly in them, the parameters are passed to the script when executed. The logic of such scripts is as follows:
- The script determines which groups this user is in.
- Selects specific groups based on a predetermined attribute (for example, by prefix!)
- Pulls “parameters” out of these groups (Description field, name of group without prefix, etc.) and starts an external command, or procedure with these parameters
As an example, I will cite a script that works according to this principle: it determines which groups the user is in, finds among them groups with the
RDP_ prefix, and creates a desktop RDP shortcut for a person with the following parameters:
- The name of the label equals the name of the group without the prefix,
- The name of the target server referenced by the RDP label is recorded in the Description group.
As a result, in order to send someone to the 1C server, it is enough to add him to the group and ask to restart the system. In addition, on the accounting terminal server, remote access is allowed only to Administrators and members of the RDP_GroupName groups.
')
' RDP- , .
' - RDP_ Description , RDP-
' AD- RDP_1C- Server1.domain.local Desription
' - , .
' RDP- .
On Error Resume Next
Set wshShell = WScript.CreateObject("WScript.Shell")
Set m_FSO = CreateObject("Scripting.FileSystemObject")
' AD
Set objSysInfo = CreateObject("ADSystemInfo")
ADSPath = "LDAP://" & objSysInfo.UserName
Set objUser = GetObject(ADSPath)
ShortUserName = objUser.SamAccountName
DomainName = objSysInfo.DomainShortName
'
DesktopPath = wshShell.SpecialFolders("Desktop")
LevelCount = 0
MaxLevelCount = 4
Status = CheckGroups(ADSPath)
'
'============ Function GetPrefixNameGroup ============
Function GetPrefixNameGroup(sString)
' Trim prefix of name group
Dim TempString
TempString = Left(sString, InStr(sString, "_"))
GetPrefixNameGroup = TempString
End Function
'=====================================================
'============ Function GetLinkNameGroup ============
Function GetLinkNameGroup(sString)
' Trim LinkName of name group
Dim TempString
TempString = Mid(sString, InStrRev(sString, "_")+1)
GetLinkNameGroup = TempString
End Function
'=====================================================
'============ Function Create RdpFile ============
Function CreateRDPFile(sString, sName)
spath = DesktopPath & "\" & sString & ".rdp"
' - - '
If m_FSO.FileExists(sPath) or m_FSO.FolderExists(sPath) Then
m_FSO.DeleteFile (sPath),1
End If
Set RDPFile = m_FSO.CreateTextFile (spath, True)
RDPFile.writeline ("screen mode id:i:2")
RDPFile.writeline ("use multimon:i:0")
RDPFile.writeline ("desktopwidth:i:1280")
RDPFile.writeline ("desktopheight:i:1024")
RDPFile.writeline ("session bpp:i:16")
RDPFile.writeline ("winposstr:s:0,1,0,0,800,600")
RDPFile.writeline ("compression:i:1")
RDPFile.writeline ("keyboardhook:i:2")
RDPFile.writeline ("audiocapturemode:i:0")
RDPFile.writeline ("videoplaybackmode:i:1")
RDPFile.writeline ("connection type:i:2")
RDPFile.writeline ("displayconnectionbar:i:1")
RDPFile.writeline ("disable wallpaper:i:1")
RDPFile.writeline ("disable full window drag:i:1")
RDPFile.writeline ("allow desktop composition:i:0")
RDPFile.writeline ("allow font smoothing:i:0")
RDPFile.writeline ("disable menu anims:i:1")
RDPFile.writeline ("disable themes:i:1")
RDPFile.writeline ("disable cursor setting:i:0")
RDPFile.writeline ("bitmapcachepersistenable:i:1")
' '
RDPFile.writeline ("full address:s:" & sName)
RDPFile.writeline ("audiomode:i:2")
RDPFile.writeline ("redirectprinters:i:0")
RDPFile.writeline ("redirectcomports:i:0")
RDPFile.writeline ("redirectsmartcards:i:0")
RDPFile.writeline ("redirectclipboard:i:1")
RDPFile.writeline ("redirectposdevices:i:0")
RDPFile.writeline ("redirectdirectx:i:1")
RDPFile.writeline ("autoreconnection enabled:i:1")
RDPFile.writeline ("authentication level:i:0")
RDPFile.writeline ("prompt for credentials:i:0")
RDPFile.writeline ("negotiate security layer:i:1")
RDPFile.writeline ("remoteapplicationmode:i:0")
RDPFile.writeline ("alternate shell:s:")
RDPFile.writeline ("shell working directory:s:")
RDPFile.writeline ("gatewayhostname:s:")
RDPFile.writeline ("gatewayusagemethod:i:4")
RDPFile.writeline ("gatewaycredentialssource:i:4")
RDPFile.writeline ("gatewayprofileusagemethod:i:0")
RDPFile.writeline ("promptcredentialonce:i:1")
' Domain\Username'
RDPFile.writeline ("username:s:" & DomainName& "\"& ShortUserName)
RDPFile.writeline ("drivestoredirect:s:")
RDPFile.close
End Function
'=====================================================
'============ Function CheckGroups ===================
Function CheckGroups(ADSPath)
Dim objUser, arrMemberOf
Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
LevelCount = LevelCount + 1
if ( LevelCount >= MaxLevelCount) then
LevelCount = LevelCount - 1
return LevelCount
end If
Set objUser = GetObject (ADSPath)
On Error Resume Next
arrMemberOf = objUser.GetEx("memberOf")
If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
LevelCount = LevelCount - 1
return LevelCount
Else
For Each Group in arrMemberOf
ADSGroup = "LDAP://" & Group
CheckGroups(ADSGroup)
WScript.Echo "Extra=" & LevelCount
Set objGroup = GetObject ( ADSGroup )
If(GetPrefixNameGroup(objGroup.CN) = "RDP_") Then
Set objGroup = GetObject ( "LDAP://" & Group)
LinkName = GetLinkNameGroup(objGroup.CN)
LinkServer = objGroup.description
LinkResult = CreateRDPFile (LinkName, LinkServer)
end If
Next
End If
LevelCount = LevelCount - 1
End Function
'=====================================================
And so as not to repeat the script sheet, and in addition to inciting the "righteous curiosity of a sysadmin", example number two will be a screenshot from AD.

Here, a similar script is used to add 1C databases to users. Moreover, as it is easy to guess, with a part of the databases, users work in the terminal (in two different) and the script for adding paths runs on the terminal itself, therefore the paths are local. With another part of the bases (payroll) —through the network, and the script runs on the workstations, which in general is not important, it doesn’t matter what ways to add to the user. If you do this yourself, do not forget that in 1C7.7 and in 1C8.X there are different principles of adding paths to the databases, respectively, either different scripts are needed, or two different functions in the script body.
It is even better to directly launch 1C itself through such a script, which will first register everything that is needed, and then launch the program.
To
be continued
PS tell me. How on Habré is better to lay out the scripts and the code in general, and then the painful long post is obtained.