Listing All Active Directory Groups - c#

The following code lists some, but not all, Active Directory Groups. Why?
I am trying to list all security groups, distribution groups, computer groups etc. Have I specified the wrong objectClass?
private static void ListGroups()
{
DirectoryEntry objADAM = default(DirectoryEntry);
DirectoryEntry objGroupEntry = default(DirectoryEntry);
DirectorySearcher objSearchADAM = default(DirectorySearcher);
SearchResultCollection objSearchResults = default(SearchResultCollection);
SearchResult myResult=null;
objADAM = new DirectoryEntry(LDAP);
objADAM.RefreshCache();
objSearchADAM = new DirectorySearcher(objADAM);
objSearchADAM.Filter = "(&(objectClass=group))";
objSearchADAM.SearchScope = SearchScope.Subtree;
objSearchResults = objSearchADAM.FindAll();
// Enumerate groups
try
{
fileGroups.AutoFlush = true;
if (objSearchResults.Count != 0)
{
foreach (SearchResult objResult in objSearchResults)
{
myResult = objResult;
objGroupEntry = objResult.GetDirectoryEntry();
Console.WriteLine(objGroupEntry.Name);
fileGroups.WriteLine(objGroupEntry.Name.Substring(3));
}
}
else
{
throw new Exception("No groups found");
}
}
catch (PrincipalException e)
{
fileErrorLog.AutoFlush = true;
fileErrorLog.WriteLine(e.Message + " " + myResult.Path);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}

If you're on .NET 3.5 or newer, you can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for a GroupPrincipal
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement

Try filter "(objectcategory=group)"
Found solution here

DirectoryEntry entry = new DirectoryEntry("ldap://ldap.gaurangjadia.com", "scott", "tiger");
DirectorySearcher dSearch = new DirectorySearcher(entry);
dSearch.Filter = "(&(objectClass=group))";
dSearch.SearchScope = SearchScope.Subtree;
SearchResultCollection results = dSearch.FindAll();
for (int i = 0; i < results.Count; i++) {
DirectoryEntry de = results[i].GetDirectoryEntry();
//TODO with "de"
}

I tried this and it worked
public ArrayList GetAllGroupNames(string ipAddress, string ouPath)
{
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = GetRootDirectoryEntry(ipAddress, ouPath);
deSearch.Filter = "(&(objectClass=group))";
SearchResultCollection results = deSearch.FindAll();
if (results.Count > 0)
{
ArrayList groupNames = new ArrayList();
foreach (SearchResult group in results)
{
var entry = new DirectoryEntry(group.Path, UserName, Password);
string shortName = entry.Name.Substring(3, entry.Name.Length - 3);
groupNames.Add(shortName);
}
return groupNames;
}
else
{
return new ArrayList();
}
}
private DirectoryEntry GetRootDirectoryEntry(string ipAddress, string domainPath, string username, string password)
{
var ldapPath = "LDAP://" + ipAddress + "/" + domainPath;
return new DirectoryEntry(ldapPath, username, password, AuthenticationTypes.Secure);
}

To retrieve a set of results that is larger than 1000 items, you must set SizeLimit to its default value (zero) and set PageSize to a value that is less than or equal to 1000.
objSearchADAM.PageSize = 1000;

you can get the all ad group details by the below powershell and if you want particular Name against of AD Group then write filter instead of *
Get-ADGroup -Filter * -properties * | Export-csv c:\csv\new.csv

Related

Unable to get complete usergroups from active directory c#

I am trying to convert some old code to use new namespaces to get the users, groups, subgroups from active directory and insert them into DB. The new code is not returning the complete list of groups a user is associated to. Some of the groups the user is associated to is not returned by the new code.
Old Code :
DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry(directoryPath));
searcher.PageSize = 1000;
searcher.Filter = "(&(objectCategory=user))";
//adding these properties assist in assuring they are returned by Active Directory
searcher.PropertiesToLoad.Add("memberOf");
searcher.PropertiesToLoad.Add("member");
searcher.PropertiesToLoad.Add("samaccountname");
searcher.PropertiesToLoad.Add("cn");
searcher.PropertiesToLoad.Add("description");
searcher.PropertiesToLoad.Add("whencreated");
searcher.PropertiesToLoad.Add("mail");
SearchResultCollection resultUsers = searcher.FindAll();
Dictionary<string, Group> groups = new Group().GetAllGroups(); //get the list of groups that were inserted into DB
foreach (SearchResult resultUser in resultUsers)
{
DirectoryEntry userEntry = resultUser.GetDirectoryEntry();
string userName = GetProperty(userEntry, "samaccountname"); //Custom method to get samaccountname
//make sure the username exists
if (userName.Length != 0)
{
User user = new User();
//set user properties
user.FullName = user.Email = GetProperty(userEntry, "cn");
user.Email = GetProperty(userEntry, "mail");
string createdDateString = GetProperty(userEntry, "whencreated");
user.CreatedDate = (createdDateString.Length > 0) ? DateTime.Parse(createdDateString) : DateTime.MinValue;
user.UserName = userName;
user.DomainName = _dataSource.UserDomainName;
//check to see if the account is disabled
ActiveDs.IADsUser objIADsUser = (ActiveDs.IADsUser)userEntry.NativeObject;
user.Inactive = objIADsUser.AccountDisabled;
//save the user
user.SaveNew();
userEntry.RefreshCache(new string[] { "tokenGroups" });
//now the attribute will be available
int count = userEntry.Properties["tokenGroups"].Count;
IdentityReferenceCollection irc = ExpandTokenGroups(userEntry).Translate(typeof(NTAccount));
foreach (IdentityReference ir in irc)
{
NTAccount testAccount;
bool isNTAccount = false;
try
{
testAccount = (NTAccount)ir;
isNTAccount = true;
}
catch
{
}
if (isNTAccount)
{
NTAccount account = (NTAccount)ir;
string groupName = account.Value.Split('\\')[1];
if (groups.ContainsKey(groupName.ToLower()))
{
Group group = groups[groupName.ToLower()];
//add user to group
UserGroupLink userGroupLink = new UserGroupLink();
userGroupLink.GroupId = group.GroupId;
userGroupLink.UserId = user.UserID;
userGroupLink.SaveNew();
}
}
}
}
}
//close connection to active directory
searcher.Dispose();
New code:
var section = (NameValueCollection)ConfigurationManager.GetSection("DataSource_ActiveDirectory1");
string domainName = section["userDomainName"];
string domainFilter = section["domainFilter"];
PrincipalContext MyPrincipalContext = new PrincipalContext(ContextType.Domain, domainName, domainFilter); //Create your domain context
GroupPrincipal FindAllGroups = new GroupPrincipal(MyPrincipalContext); //group principal to search for all group.
UserPrincipal FindAllUsers = new UserPrincipal(MyPrincipalContext); //user principal to search for all users.
PrincipalSearcher UserSearcher = new PrincipalSearcher(FindAllUsers); //search results for user
PrincipalSearchResult<Principal> UserReults = UserSearcher.FindAll(); //find all users
PrincipalSearcher MySearcher = new PrincipalSearcher(FindAllGroups); //search results for groups
PrincipalSearchResult<Principal> GroupResults = MySearcher.FindAll(); //search all groups
ArrayList AllUsers = new ArrayList();
foreach (Principal UserReult in UserReults)
{
UserPrincipal UserName = UserPrincipal.FindByIdentity(MyPrincipalContext, IdentityType.SamAccountName, UserReult.SamAccountName);
//logic to save users to DB
}
foreach (Principal UserName in AllUsers)
{
foreach (Principal FindParentGroup in UserName.GetGroups())
{
string ParentGroupEntry = FindParentGroup.SamAccountName;
if (ParentGroupEntry != null || ParentGroupEntry.Length > 0)
{
//Insert into DB
}
}
}

ASP.NET LDAP SearchResults Properties returning Byte Array

I am using DirectorySearcher to try and get a list of users in AD to sync them with my App and have copied code from various SO sources, however I am not getting any property values. I'm using the following code:
DirectorySearcher search = new DirectorySearcher();
SearchResultCollection results = null;
string sDefaultOU = "LDAP://...";
DirectoryEntry de = new DirectoryEntry(sDefaultOU);
string userName = "DonaldDuck";
search = new DirectorySearcher
{
SearchRoot = de,
PropertiesToLoad = { "displayname", "sAMAccountName"},
Filter = "(sAMAccountName=" + userName + ")"
};
results = search.FindAll();
foreach (SearchResult result in results)
{
String name;
if (result.Properties["sAMAccountName"].Count > 0)
{
name = result.Properties["sAMAccountName"][0].ToString();
}
}
However, instead of name being equal to to "DonaldDuck", it will be "Byte[10]" or Byte[x] where x is the length.
Can anyone see what I am doing wrong.
If I add a filter it returns one user, so I am pretty sure the code is working in terms of searching
Apparently this issue has been faced by others: LDAP DirectoryEntry SearchResult returns data differently in Windows 8 than Win7
AD is using LDAPv3 encoding the values using UTF8, the solution mentioned in the link above might work for you:
if (result.Properties["sAMAccountName"][0].GetType().IsArray)
{
name = System.Text.Encoding.UTF8.GetString((byte[])result.Properties["sAMAccountName"][0]);
}
else
{
name = result.Properties["sAMAccountName"][0].ToString();
}
instead of
foreach (SearchResult result in results)
{
String name;
if (result.Properties["sAMAccountName"].Count > 0)
{
name = result.Properties["sAMAccountName"][0].ToString();
}
}
try  
foreach (SearchResult result in results)
{
String name;
if (result.Properties["sAMAccountName"].Count > 0)
{
var thisDE=result.GetDirectoryEntry();
name = thisDE.Properties["sAMAccountName"].Value.ToString();
}
}
EDIT: Example
I use this helper method to search my domain (when userDomainAndName="DOMAIN\UserName") but you should be able to tweak it for what you want.
public static DirectoryEntry GetUserDirectoryEntryFromCurrentDomain(string userDomainAndName)
{
var Split = userDomainAndName.Split(#"\\".ToCharArray());
var DomainNetBiosNAme = Split[0];
var UserName = Split[1];
var QueryString = $"(&(objectCategory=person)(objectClass=user)(sAMAccountName={UserName}))";
DirectoryEntry rootDSE = GetDirectoryObject(
"LDAP://" + DomainNetBiosNAme + "/rootDSE");
string domain = "LDAP://" + (string)rootDSE.Properties[
"defaultNamingContext"][0];
var Searcher = new DirectorySearcher(new DirectoryEntry(domain), QueryString);
var Result = Searcher.FindOne();
var tReturn = Result.GetDirectoryEntry();
return tReturn;
}
then to get my users PrimarySMTP address (for example)..
var TheUsersDirectoryEntry=GetUserDirectoryEntryFromCurrentDomain(userDomainAndName);
var TheUsersPrimarySMTP=TheUsersDirectoryEntry.Properties["mail"].Value.ToString();

How to retrieve all users of Active Directory?

I use following code to retrieve all users of active directory but not all users retrieved. Should I include something else in Filter?
this is simplified code.
DirectoryEntry entry = new DirectoryEntry("LDAP://" + Bous.DomainName, Bous.UserName, Bous.Password);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = ("(&(objectCategory=person)(objectClass=user))");
foreach (SearchResult result in mySearcher.FindAll())
{
dr = dt.NewRow();
ResultPropertyCollection myResultPropColl = result.Properties;
dr[0] = myResultPropColl["samaccountname"][0].ToString() + "#" + Bous.DomainName;
dt.Rows.Add(dr);
}
Try this one:
DirectoryEntry entry = new DirectoryEntry("LDAP://" + Bous.DomainName, Bous.UserName, Bous.Password);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.PageSize = 1000; // <--- Important!
mySearcher.Filter = ("(&(objectCategory=person)(objectClass=user))");
foreach (SearchResult result in mySearcher.FindAll())
{
dr = dt.NewRow();
ResultPropertyCollection myResultPropColl = result.Properties;
dr[0] = myResultPropColl["samaccountname"][0].ToString() + "#" + Bous.DomainName;
dt.Rows.Add(dr);
}
If you're on .NET 3.5 or newer, you can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// define a "query-by-example" principal - here, we search for UserPrincipal (users)
UserPrincipal qbeUser = new UserPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
}
If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
...
protected static UserPrincipal QueryFilterUsers(string FilterFullName, string FilterDescription, string FilterLogin, string FilterPhone, string FilterEmail)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, _Domain);
UserPrincipal _UserPrincipal = new UserPrincipal(ctx);
_UserPrincipal.SamAccountName = "*" + ((!string.IsNullOrEmpty(FilterLogin)) ? FilterLogin.Trim() + "*" : "");
if (!string.IsNullOrEmpty(FilterFullName)) _UserPrincipal.DisplayName = "*" + FilterFullName.Trim() + "*";
if (!string.IsNullOrEmpty(FilterDescription)) _UserPrincipal.Description = "*" + FilterDescription.Trim() + "*";
if (!string.IsNullOrEmpty(FilterPhone)) _UserPrincipal.VoiceTelephoneNumber = "*" + FilterPhone.Trim() + "*" ;
if (!string.IsNullOrEmpty(FilterEmail)) _UserPrincipal.EmailAddress = "*" + FilterEmail.Trim() + "*";
return _UserPrincipal;
}
//Получение списков
public static List<Principal> GetUsersPrincipalList(string FilterFullName, string FilterDescription, string FilterLogin, string FilterPhone, string FilterEmail)
{
PrincipalSearcher _PrincipalSearcher = new PrincipalSearcher();
_PrincipalSearcher.QueryFilter = QueryFilterUsers(FilterFullName, FilterDescription, FilterLogin, FilterPhone, FilterEmail);
(_PrincipalSearcher.GetUnderlyingSearcher() as DirectorySearcher).PageSize = _PageSize;
(_PrincipalSearcher.GetUnderlyingSearcher() as DirectorySearcher).SizeLimit = _SizeLimit;
return _PrincipalSearcher.FindAll().ToList();
}

How to retrieve SAMAccountName from Active Directory

I implemented a method that returns a list of Active Directory users, I would like to retrieve SAMAccountName like this Domain\Administrator.
This is the method I use:
public Collection<software_user> GetUsersFromAD(String adConnectionString)
{
var users = new Collection<software_user>();
using (var directoryEntry = new DirectoryEntry(adConnectionString))
{
var directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = "(&(objectClass=user))";
var propertiesToLoad = new[]
{
"SAMAccountName",
"displayName",
"givenName",
"sn",
"mail",
"userAccountControl",
"objectSid"
};
directorySearcher.PropertiesToLoad.AddRange(propertiesToLoad);
foreach (SearchResult searchEntry in directorySearcher.FindAll())
{
var userEntry = searchEntry.GetDirectoryEntry();
var ldapUser = new software_user();
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["displayName"].Value);
if (string.IsNullOrEmpty(ldapUser.User_name))
continue;
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["SAMAccountName"].Value);
ldapUser.email = NullHandler.GetString(userEntry.Properties["mail"].Value);
ldapUser.user_shortname = NullHandler.GetString(userEntry.Properties["givenName"].Value);
var userAccountControl = (int)userEntry.Properties["userAccountControl"].Value;
//ldapUser.IsActive = (userAccountControl & UF_ACCOUNTDISABLE) != UF_ACCOUNTDISABLE;
var sid = new SecurityIdentifier((byte[])userEntry.Properties["objectSid"][0], 0).Value;
//ldapUser.SId = sid;
users.Add(ldapUser);
}
}
return users;
}
First off: Domain\Administrator is NOT a SAM account name! The SAM account name is a unique (over the whole domain) name of up to 20 characters in length - typically it's your "Windows user name" (e.g. Administrator) - but it does NOT include the domain name. That value made up of domain\username is NOT stored in Active Directory anywhere!
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
// do something here....
string samAccountName = user.SamAccountName;
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
If you want to search for a whole group of users (or groups or computers), you can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for a UserPrincipal
// and with the last name (Surname) of "Miller"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.Surname = "Miller";
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
You can translate a user as a Distinguished name to DOMAIN\SAMaccount form using the Object's SID, and the System.Security.Principal.SecurityIdentifier.Translate command.
public Collection<software_user> GetUsersFromAD(String adConnectionString)
{
var users = new Collection<software_user>();
using (var directoryEntry = new DirectoryEntry(adConnectionString))
{
var directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = "(&(objectClass=user))";
var propertiesToLoad = new[]
{
"SAMAccountName",
"displayName",
"givenName",
"sn",
"mail",
"userAccountControl",
"objectSid"
};
directorySearcher.PropertiesToLoad.AddRange(propertiesToLoad);
foreach (SearchResult searchEntry in directorySearcher.FindAll())
{
var userEntry = searchEntry.GetDirectoryEntry();
var ldapUser = new software_user();
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["displayName"].Value);
if (string.IsNullOrEmpty(ldapUser.User_name))
continue;
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["SAMAccountName"].Value);
ldapUser.email = NullHandler.GetString(userEntry.Properties["mail"].Value);
ldapUser.user_shortname = NullHandler.GetString(userEntry.Properties["givenName"].Value);
var userAccountControl = (int)userEntry.Properties["userAccountControl"].Value;
//ldapUser.IsActive = (userAccountControl & UF_ACCOUNTDISABLE) != UF_ACCOUNTDISABLE;
SecurityIdentifier sid = new SecurityIdentifier((byte[])userEntry.Properties["objectSid"][0], 0).Value;
--> NTAccount account = (NTAccount) sid.Translate(typeof(NTAccount));
--> ldapUser.User_name = account.ToString();
//ldapUser.SId = sid;
users.Add(ldapUser);
}
}
return users;
}

How to find users in AD that belong to a group, and just get their SAMAccountName, and SID?

I just want a user to be able to type in a group name in a textbox, and return just their login name and their SID.
So far i have this, and that loads the users in the group but im unsure how to extract the login and SID.
SearchResult result;
DirectorySearcher search = new DirectorySearcher();
search.Filter = String.Format("(cn={0})", txtGroup.Text);
search.PropertiesToLoad.Add("member");
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("objectGUID");
result = search.FindOne();
StringBuilder userNames = new StringBuilder();
if (result != null)
{
for (int counter = 0; counter <
result.Properties["member"].Count; counter++)
{
string user = (string)result.Properties["member"][counter];
userNames.AppendLine(user);
}
}
lblResults.Text = userNames.ToString();
The propertie wich contains SID is called objectSid, and the propertie wich contain th login is sAMAccountName for the NT4 compatible version and userPrincipalName. You'd better work with #Virkkunen advice.
static void Main(string[] args)
{
/* Connection to Active Directory
*/
DirectoryEntry deBase = new DirectoryEntry("LDAP://192.168.183.138:389/dc=societe,dc=fr", "administrateur", "pwd");
/* Directory Search
*/
DirectorySearcher dsLookForGrp = new DirectorySearcher(deBase);
dsLookForGrp.Filter = String.Format("(cn={0})", "yourgroup");
dsLookForGrp.SearchScope = SearchScope.Subtree;
dsLookForGrp.PropertiesToLoad.Add("distinguishedName");
SearchResult srcGrp = dsLookForGrp.FindOne();
/* Directory Search
*/
DirectorySearcher dsLookForUsers = new DirectorySearcher(deBase);
dsLookForUsers.Filter = String.Format("(&(objectCategory=person)(memberOf={0}))", srcGrp.Properties["distinguishedName"][0]);
dsLookForUsers.SearchScope = SearchScope.Subtree;
dsLookForUsers.PropertiesToLoad.Add("objectSid");
dsLookForUsers.PropertiesToLoad.Add("userPrincipalName ");
dsLookForUsers.PropertiesToLoad.Add("sAMAccountName");
SearchResultCollection srcLstUsers = dsLookForUsers.FindAll();
foreach (SearchResult sruser in srcLstUsers)
{
Console.WriteLine("{0}", sruser.Path);
SecurityIdentifier sid = new SecurityIdentifier((byte[]) sruser.Properties["objectSid"][0], 0);
Console.WriteLine(sid.ToString());
foreach (string property in sruser.Properties.PropertyNames)
{
Console.WriteLine("\t{0} : {1} ", property, sruser.Properties[property][0]);
}
}
}
I think it would work better if you reverse your query:
(&(objectClass=user)(memberOf={0}))
This way you'll directly get back a list of users by using FindAll. Don't forget to add sAMAccountName etc into PropertiesToLoad.

Categories