Some administrators prefer assigning permissions based on Active Directory placement, similar to how you can assign permissions to containers in NDS. Because this capability is not available natively in Active Directory, they spend a lot of time keeping group membership and objects within an organizational unit in sync.
This is my implementation of syncing Shadow groups with organizational units.
1) Download ShadowGroup tool (http://blog.ittelligence.com/wp-content/uploads/2018/07/ShadowGroups.zip) and extract to a folder on your file server.
2) Run Configurator.exe (Configurator Editor).
a) On the Encrypt tab, enter the password for the account that will be performing the cleanup task. Encrypt it with key vEgEAgUlpSSIj8Le and record the encrypted password.
b) On the Settings tab, enter the distinguished name, fully qualified domain name, NetBIOS, and username and the encrypted password recorded in step 2a.
c) On the ShadowGroups tab, specify the group name and the distinguished name of an organizational unit that group should shadow (+ or INS to add, - or DEL to delete, Enter or double-click to edit)
public static bool ShadowGroup(Models.DomainInfo DomainInfo, string OUPath, string GroupName, out string Message)
{
try
{
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://" + DomainInfo.FQDN + "/" + OUPath, DomainInfo.NetBIOS + @"\" + DomainInfo.UserName, DomainInfo.Password);
DirectoryEntry groupDirectoryEntry;
string message;
if (GetGroupDEByName(DomainInfo, GroupName, out groupDirectoryEntry, out message))
{
// Clear all members
if (ClearGroupMembers(groupDirectoryEntry, out message))
{
DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.PageSize = 1000;
directorySearcher.PropertiesToLoad.Add("cn");
directorySearcher.PropertiesToLoad.Add("distinguishedName");
directorySearcher.PropertiesToLoad.Add("objectSid");
// Get users and groups from the specified OU
directorySearcher.Filter = "(|(&(objectClass=person)(objectClass=user))(objectClass=group))";
foreach (SearchResult searchResult in directorySearcher.FindAll())
{
try
{
DirectoryEntry childDirectoryEntry = searchResult.GetDirectoryEntry();
string distinguishedName = "";
string groupSID = "";
SecurityIdentifier sid;
try { sid = new SecurityIdentifier(childDirectoryEntry.Properties["objectSid"][0] as byte[], 0); groupSID = sid.Value; } catch { }
try { distinguishedName = childDirectoryEntry.Properties["distinguishedName"].Value.ToString(); } catch { }
// Only add objects to group that have a security identifier
if (groupSID != "")
{
groupDirectoryEntry.Properties["member"].Add(distinguishedName);
groupDirectoryEntry.CommitChanges();
}
}
catch
{
// Item error
}
}
Message = message;
return true;
}
else
{
Message = message;
return false;
}
}
else
{
Message = message;
return false;
}
}
catch (Exception ex)
{
Message = ex.Message;
}
return false;
}
public static bool ClearGroupMembers(DirectoryEntry GroupDE, out string Message)
{
try
{
// Get a collection of the current group members
PropertyValueCollection members = GroupDE.Properties["member"];
string groupName = GroupDE.Properties["sAMAccountName"].Value.ToString();
// Remove these members one at a time
for (int counter = members.Count - 1; counter >= 0; counter--)
{
members.RemoveAt(counter);
GroupDE.CommitChanges();
GroupDE.Close();
}
Message = $"Group \"{groupName}\" cleared";
return true;
}
catch (Exception ex)
{
Message = ex.Message;
return false;
}
}
public static bool GetGroupDEByName(Models.DomainInfo DomainInfo, string GroupName, out DirectoryEntry GroupDE, out string Message)
{
try
{
using (DirectoryEntry de = new DirectoryEntry("LDAP://" + DomainInfo.FQDN, DomainInfo.NetBIOS + @"\" + DomainInfo.UserName, DomainInfo.Password))
{
using (DirectorySearcher groupDS = new DirectorySearcher(de))
{
string queryGroup = $"(&(objectCategory=group)(CN={GroupName}))";
groupDS.Filter = queryGroup;
groupDS.PropertiesToLoad.Add("memberOf");
groupDS.PropertiesToLoad.Add("member");
groupDS.PropertiesToLoad.Add("name");
groupDS.PropertiesToLoad.Add("sAMAccountName");
groupDS.PropertiesToLoad.Add("distinguishedName");
SearchResult groupSearchResult = groupDS.FindOne();
if (groupSearchResult != null)
{
Message = $"Group \"{GroupName}\" found";
GroupDE = groupSearchResult.GetDirectoryEntry();
return true;
}
else
{
Message = $"Group \"{GroupName}\" not found";
GroupDE = null;
return false;
}
}
}
}
catch (Exception ex)
{
Message = ex.Message;
GroupDE = null;
return false;
}
}
I hope you found this tutorial useful. You are encouraged to ask questions, report any bugs or make any other comments about it below.
Note: If you need further "Support" about this topic, please consider using the Ask a Question feature of Experts Exchange. I monitor questions asked and would be pleased to provide any additional support required in questions asked in this manner, along with other EE experts...
Please do not forget to press the "Thumb's Up" button if you think this article was helpful and valuable for EE members.
It also provides me with positive feedback. Thank you!
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (0)