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
}
}
}
Related
I'm trying to get bit locker recovery information for all users from active directory via below functions.
I've tried many different solution but none of them solved my problem.
I can get most of the computer properties like Operation System,Service Pack expect bit locker info.
Is there any special permission or method to search with msFVE-RecoveryInformation ?
Method 1:
DirectoryEntry child = new DirectoryEntry("LDAP://XXXXX");
DirectoryEntries enteries = child.Children;
DirectorySearcher ds = new DirectorySearcher(child);
ds.Filter = "(&(objectCategory=Computer)(cn=computerName))";
ds.SearchScope = SearchScope.Subtree;
SearchResultCollection item = ds.FindAll();
//string dn = item.GetDirectoryEntry().Properties["distinguishedname"].Value.ToString();
string temp1 = System.DirectoryServices.AccountManagement.UserPrincipal.Current.DistinguishedName;
child = new DirectoryEntry(("LDAP://" + temp1), "XXXXX", "XXXXX");
enteries = child.Children;
ds = new DirectorySearcher(child);
ds.Filter = "(objectClass=msFVE-RecoveryInformation)";
ds.SearchScope = SearchScope.Subtree;
SearchResultCollection result = ds.FindAll();
if (result.Count > 0)
{
foreach (SearchResult sr in result)
{
string recoveryKeyPackage = sr.GetDirectoryEntry().Properties["msFVE-KeyPackage"].Value.ToString();
string recoveryGUID = sr.GetDirectoryEntry().Properties["msFVE-RecoveryGuid"].Value.ToString();
string recoveryPassword = sr.GetDirectoryEntry().Properties["msFVE-RecoveryPassword"].Value.ToString();
string recoveryVolumeGUID = sr.GetDirectoryEntry().Properties["msFVE-VolumeGuid"].Value.ToString();
}
}
else
{
Console.Write ("No recovery information found!");
}
Method 2:
public Dictionary<string, string> GetBitlockerKeys(string computerName)
{
DirectoryEntry dEntry = new DirectoryEntry("LDAP://XXXX");
var keys = new Dictionary<string, string>();
using (var computerObject = dEntry)
{
var children = computerObject.Children;
var schemaFilter = children.SchemaFilter;
schemaFilter.Add("msFVE-RecoveryInformation");
foreach (DirectoryEntry child in children) using (child)
{
var recoveryGuid = new Guid((byte[])child.Properties["msFVE-RecoveryGuid"].Value).ToString();
var recoveryPassword = child.Properties["msFVE-RecoveryPassword"].Value.ToString();
if (!keys.ContainsKey(recoveryGuid))
{
keys.Add(recoveryGuid, recoveryPassword);
}
}
}
return keys;
}
If I have the name of an Active Directory group, how can I get a list of the members or their email addresses?
void Main()
{
string groupName = "somegroup";
string domainName = "somedomain";
using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domainName))
{
using(GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, groupName))
{
var sams = from x in grp.GetMembers(true) select new {x.SamAccountName, };
var users = from sam in sams.Distinct()
let usr = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, sam.SamAccountName)
select new { usr.SamAccountName, usr.DisplayName, usr.EmailAddress};
//do something with users...
}
}
}
in this url are a good and complete articule about AD with C# http://www.codeproject.com/Articles/18102/Howto-Almost-Everything-In-Active-Directory-via-C#42, user are stored as DiretoryEntry review the property Properties
http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.properties(v=vs.100).aspx
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;
}
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.
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