Directory Services, Search all available providers - c#

I have the following method used for searching for a User Group either on the local computer (done first) or in the Current Forest.
public string FindUserGroup(string group)
{
//Search local computer
using (DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry()))
{
searcher.Filter = "(&(objectClass=group)(|(cn=" + group + ")(dn=" + group + ")))";
SearchResult result = searcher.FindOne();
if (result != null)
return TranslateDirectoryEntryPath(result.GetDirectoryEntry().Path);
}
//Search current forest
Forest forest = Forest.GetCurrentForest();
foreach (Domain domain1 in forest.Domains)
{
using (DirectorySearcher searcher = new DirectorySearcher(domain1.GetDirectoryEntry()))
{
searcher.Filter = "(&(objectClass=group)(|(cn=" + group + ")(dn=" + group + ")))";
SearchResult result = searcher.FindOne();
if (result != null)
return TranslateDirectoryEntryPath(result.GetDirectoryEntry().Path);
}
}
return string.Empty;
}
My problem is that we as an example have say "domain.local" and "mydomain.local", and my current login is bound to "domain.local", then using below won't be able to find anything in "mydomain.local", even if I through the Windows User Interface is able to.
How can I search all viewable providers from my computers perspective when I don't nessesarily know them all? Do I REALLY have to do the Registry Work my self?
Edit:
One difference in the 2 domains is the "level" they are on when I in an object browser dialog chooses "Locations", it layouts as:
Computer
Entire Direction
domain.local
mydomain.local
So "mydomain.local" excists outside what is referred to as "Entire Directory", yet my computer can locate it, if that makes any difference?

I don't see a problem as this code here would have already be binded to the other domains.
foreach (Domain domain1 in forest.Domains)
{
using (DirectorySearcher searcher = new DirectorySearcher(domain1.GetDirectoryEntry()))
{
Are you trying to say that later on you're binding a DirectoryEntry on your own, and you can't find objects from other domain?

Related

Different result with DirectorySearcher

I wrote a small app to check AD group members. When I execute the following code on my pc, It works well, the SearchResult contains the "member" property, however when I run the same exe on the server or on an another computer the "member" property is missing. The usnchanged and usncreated will be different also. I run the exe with the same user on every pc. What can cause this?
...
using (DirectorySearcher searcher = new DirectorySearcher())
{
searcher.CacheResults = false;
searcher.Filter = "(&(objectClass=group)(cn=" + ADName + "))";
searcher.SizeLimit = int.MaxValue;
searcher.PageSize = int.MaxValue;
if (!DirectoryEntry.Exists(ADPath))
{
return null;
}
searcher.SearchRoot = new DirectoryEntry(ADPath);
using (SearchResultCollection collection = searcher.FindAll())
{
if (collection.Count == 1)
{
return collection[0];
}
}
}
...
The group membership data is not replicated to the global catalog. The query might work sometimes, if you happen to connect to the domain controller with the actual membership data. On other machines, you probably connect to other domain controllers, of different domains, where the information is not available.
You might want to connect to a domain controller in the actual domain, not to the global catalog.

Different results for Active Directory "memberof" on different computers

I have some code that retrieves the Active Directory groups that a user is a member of. On localhost it returns the correct results, but when deployed to a another computer (web server on same network) it returns much less results.
I am specifying AD server and a special user name and password I was given by administrators to access.
DirectoryEntry de = new DirectoryEntry("LDAP://***:389", "***", "***");
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + search + "))";
ds.SearchScope = SearchScope.Subtree;
ds.PropertiesToLoad.Add("*");
SearchResult rs = ds.FindOne();
if (rs != null)
{
if (rs.GetDirectoryEntry().Properties["memberof"].Value != null)
//rest of code removed
I also tried a different method and the results were also different...
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "***, "***", "***"))
{
UserPrincipal user = UserPrincipal.FindByIdentity(pc, name);
if (user != null)
{
List<string> groups = new List<string>();
PrincipalSearchResult<Principal> groups2 = user.GetAuthorizationGroups();
//rest of code removed
I would have thought that by specifying a user name and password that the result should be the same. Any idea why this is happening?
These are different because they're retrieving different datasets. The memberOf attribute is constructed on the fly and it will give you the groups the user is a /direct/ member of. The GetAuthorizationGroups() call, on the other hand, will give you all the security groups that the user is transitively a member of. It does this by looking at the tokenGroups attribute in AD.

Loading the active directory user and their associated Computers

Hello Everyone i am trying to develop a program that will list will all the user of Active Directory and when i select one user the program should be able to show the computers associated with that user. i.e the Computers that are accessible to that AD user.
I have written code to list all user but no idea how to list the computers associated with that user.
Here is my code to load AD User into datatable:
DataTable dtUser= new DataTable();
try
{
DirectoryEntry dom = Domain.GetComputerDomain().GetDirectoryEntry();
DirectorySearcher dsAllUsers = new DirectorySearcher(dom);
dsAllUsers.SearchScope = SearchScope.Subtree;
dsAllUsers.Filter = "(objectCategory=Person)";
SearchResultCollection result = dsAllUsers.FindAll();
dtUser.Columns.Add("CustodianName");
dtUser.Columns.Add("Email");
dtUser.Columns.Add("Title");
dtUser.Columns.Add("Dept.");
foreach (SearchResult rs in result)
{
DataRow newRow = dtUser.NewRow();
if (rs.GetDirectoryEntry().Properties["samaccountname"].Value != null)
newRow["CustodianName"] = rs.GetDirectoryEntry().Properties["samaccountname"].Value.ToString();
if (rs.GetDirectoryEntry().Properties["mail"].Value != null)
newRow["Email"] = rs.GetDirectoryEntry().Properties["mail"].Value.ToString();
if (rs.GetDirectoryEntry().Properties["title"].Value != null)
newRow["Title"] = rs.GetDirectoryEntry().Properties["title"].Value.ToString();
if (rs.GetDirectoryEntry().Properties["department"].Value != null)
newRow["Dept."] = rs.GetDirectoryEntry().Properties["department"].Value.ToString();
dtUser.Rows.Add(newRow);
}
return dtUser;
}
catch (Exception)
{
throw;
}
I don't believe standard LDAP/Active Directory has anything like this.
Computers are just another class of AD objects - but there's no "link" between a user and one (or multiple) computer(s) - there's no belongsTo attribute on the computer class, nor is there a computers collection on User.
If your organization has implemented an extension to the default AD schema (which is entirely possible!), it's a custom solution, and then you must know what it is! :-)

Search Active Directory for computer name(s) using user input

Hello I'm stuck trying to add a function to my Windows forms program that allows a user to type in a textbox what computer or computers they would like to search for in Active Directory. The user would input the search string in a textbox then hit a button and the computers that match that search result would appear in a separate search box. Here is my code so far.
I would also like each computer name to be on a separate line such as:
computername1
computername2
computername3
Thanks!
This is what inside the button looks like:
List<string> hosts = new List<string>();
DirectoryEntry de = new DirectoryEntry();
de.Path = "LDAP://servername";
try
{
string adser = txtAd.Text; //textbox user inputs computer to search for
DirectorySearcher ser = new DirectorySearcher(de);
ser.Filter = "(&(ObjectCategory=computer)(cn=" + adser + "))";
ser.PropertiesToLoad.Add("name");
SearchResultCollection results = ser.FindAll();
foreach (SearchResult res in results)
//"CN=SGSVG007DC"
{
string computername = res.GetDirectoryEntry().Properties["Name"].Value.ToString();
hosts.Add(computername);
//string[] temp = res.Path.Split(','); //temp[0] would contain the computer name ex: cn=computerName,..
//string adcomp = (temp[0].Substring(10));
//txtcomputers.Text = adcomp.ToString();
}
txtcomputers.Text = hosts.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
de.Dispose();//Clean up resources
}
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 the System.DirectoryServices.AccountManagement namespace
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a computer
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(ctx, "SomeComputerName");
if (computer != null)
{
// do something here....
}
}
If you don't need to find a single computer, but search for a whole list of computers, you can use the new PrincipalSearcher interface, which basically allows you to set up a "QBE" (query-by-example) object you're looking for, defining the search criteria, and then search for matches for those criteria.
The new S.DS.AM namespace makes it really easy to play around with users and groups in AD!

Getting users of a computer

I am trying to get the list of local users of a computer using the following code.
internal void GetUsers()
{
try
{
List<string> adUsers = new List<string>();
DirectoryEntry directoryEntry = new DirectoryEntry("WinNT://" + Environment.MachineName);
foreach (DirectoryEntry child in directoryEntry.Children)
{
if (child.SchemaClassName.Equals("User", StringComparison.OrdinalIgnoreCase))
{
adUsers.Add(child.Name);
}
}
}
catch (Exception ex)
{
//Exception
}
}
This code works fine in my computer. However, when I tested it on a few other computers, the following system users were included in the list:
ASPNET,
HelpAssistant
Could some one throw some light on how I can get rid of these system users and get only users who actually log in, ie, normal users.
Thanks,
Ram
Not an answer as such, but some suggestions that might help.
I think the problem is that those accounts aren't real system accounts, so might not be so easy to distinguish.
You could look at the WMI classes Win32_UserAccount and Win32_UserProfile and see if there are any properties in there that might indicate which user accounts are normal ones and which ones are the ones you mention. Specifically, maybe the 'SIDType' or 'AccountType' properties of Win32_UserAccount or maybe the Special property of the Win32_UserProfile class.
Might be other WMI classes that might be worth looking at as well.
Or there might be some way that you can query if a user account has the interactive logon right (which I assume those two accounts might not have normally).
Have you tried enumerating the Properties collection on DirectoryEntry?
using (DirectoryEntry dirEntry = new DirectoryEntry(strchild))
{
foreach (string strPropertyName in dirEntry.Properties.PropertyNames)
{
Console.WriteLine(strPropertyName + " " + dirEntry.Properties[strPropertyName].Value.ToString());
}
}
Other than that, you may have to do an LDAP search on Active Directory to match the UserName you have found to an ActiveDirectory user.
Have a look at this article.
http://www.codeproject.com/KB/system/everythingInAD.aspx
Have fun.
The following code will get you the local users that actually have local accessible folders.
var localDrives = Environment.GetLogicalDrives();
var localUsers = new List<string>();
var query = new SelectQuery("Win32_UserAccount") { Condition = "SIDType = 1 AND AccountType = 512" };
var searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject envVar in searcher.Get())
{
foreach (string drive in localDrives)
{
var dir = Path.Combine(String.Format("{0}Users", drive), envVar["name"].ToString());
if (Directory.Exists(dir))
{
localUsers.Add(envVar["name"].ToString());
}
}
}

Categories