I have a windows group called "windgrp" it has three members in it:
Administrators
testDomain.Administrator
user1
I have this code to display the members present in a group:
using (DirectoryEntry groupEntry =
new DirectoryEntry("WinNT://./" + userGroupName + ",group"))
{
foreach (object member in (IEnumerable)groupEntry.Invoke("Members"))
{
using (DirectoryEntry memberEntry = new DirectoryEntry(member))
{
listbox.itms.add(memberentry.name);
}
}
}
This gives me the result:
Administrator
Administrator
user
It does not show me to which domain the 2nd entry belongs to.
How can I get the domain?
You need to walk up the hierarchy of objects. So if you have your user, you can start recursion from there up, looking for schema classes that satisfy your search criteria.
public DirectoryEntry FindDomain(DirectoryEntry memberEntry)
{
if (memberEntry.SchemaClassName.ToLower().Contains("domain")
return memberEntry;
if (memberEntry.Parent !=null)
return FindDomain(memberEntry.Parent);
return null;
}
Related
I need to show all my security groups and the users that are members of the security groups in a listView.
At the moment I can display all the security groups but not sure how to display the users in the security group.
Here is my code I am currently using:
private void Security_group_btn_Click(object sender, EventArgs e)
{
DirectorySearcher searcher = new DirectorySearcher(DomainName);
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, DomainName);
UserPrincipal userPrin = new UserPrincipal(ctx);
userPrin.Name = "*";
var search = new System.DirectoryServices.AccountManagement.PrincipalSearcher();
search.QueryFilter = userPrin;
var results = searcher.FindAll();
ListView lvwListView = this.security_listView;
lvwListView.Clear();
lvwListView.Columns.Add("Security Group", 175, HorizontalAlignment.Left);
lvwListView.Columns.Add("Users", 175, HorizontalAlignment.Left);
searcher.Filter = "(&(objectClass=group))";
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("sAMAccountName");
SearchResultCollection result = searcher.FindAll();
foreach (SearchResult entry in result)
{
lvwListView.Items.Add(entry.GetDirectoryEntry().Properties["sAMAccountName"].Value.ToString());
}
result.Dispose();
searcher.Dispose();
}
}
}
So basically I would like to display something like this in my ListView:
Security Group Name
Users User1
User2
User3
Administrators User1
User2
User3
User4
Thanks
First, be careful of this:
lvwListView.Items.Add(entry.GetDirectoryEntry().Properties["sAMAccountName"].Value.ToString());
Particularly, using GetDirectoryEntry() just to get a value. When you get a value using DirectoryEntry.Properties, it checks to see if it already has the value you're asking for in the cache. If not, it asks AD for every attribute that has a value, which will usually be a whole lot more data than you actually need. Since you're looping over a bunch of accounts, that can significantly slow you down.
You are already asking for the sAMAccountName in the search results, since you used searcher.PropertiesToLoad.Add("sAMAccountName"), so you can pull the value from the SearchResult object directly:
lvwListView.Items.Add((string) entry.Properties["sAMAccountName"][0]);
I talk more about that in an article I wrote about better performance when programming with Active Directory.
Now to actually answer your question:
Getting the members is a different story. You can ask for the member attribute in the search, but you get problems when a group has more than 1500 members. You have to ask for the members in pages. But also, you have to decide how you are going to handle nested groups: when a group is a member of a group. Do you want to just list that group name? Or do you want to look inside that group and get those members too?
I wrote a whole article about this too: Find all the members of a group
But it's more than likely you can just use one of the sample methods I show in that article. This will take a DirectoryEntry object of a group, and give you a list of strings containing the DOMAIN\username of each object inside the group (you can change that if you want). You can use the recursive parameter to decide what you want to do with nested groups.
public static IEnumerable<string> GetGroupMemberList(DirectoryEntry group, bool recursive = false) {
var members = new List<string>();
group.RefreshCache(new[] { "member" });
while (true) {
var memberDns = group.Properties["member"];
foreach (string member in memberDns) {
using (var memberDe = new DirectoryEntry($"LDAP://{member.Replace("/", "\\/")}")) {
memberDe.RefreshCache(new[] { "objectClass", "msDS-PrincipalName", "cn" });
if (recursive && memberDe.Properties["objectClass"].Contains("group")) {
members.AddRange(GetGroupMemberList(memberDe, true));
} else {
var username = memberDe.Properties["msDS-PrincipalName"].Value.ToString();
if (!string.IsNullOrEmpty(username)) {
members.Add(username);
}
}
}
}
if (memberDns.Count == 0) break;
try {
group.RefreshCache(new[] {$"member;range={members.Count}-*"});
} catch (COMException e) {
if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
break;
}
throw;
}
}
return members;
}
You would call it from your code like this:
var members = GetGroupMemberList(entry.GetDirectoryEntry());
Then you can display them however you want.
This will work fine if you are only working in a single AD forest. But if your domain trusts other domains outside your forest and you can expect to see users from those domains in the groups you are looking at, then you need to account for that. But I cover that in that article. I also cover primary groups there too, which is rare that you need to care about, but you might.
Update: To add two columns in a ListViewItem, you have to create it separately. You can use the constructor that takes a string array of the "subitems", as they call it.
You could put something like this inside your loop where you loop through the members, where groupName is the name of the group and member is the name of the group member.
lvwListView.Items.Add(new ListViewItem(new [] {
groupName,
member
});
If you only want the groupName on the first one, then you can just put an empty string ("") instead of groupName for the others.
There are two domains Domain A and Domain B having mutual trust between them (forest level trust).
'DomainA\BiggerGroup' is a user group (Domain local scope) in domain A.
'DomainB\SmallGroup' is a user group (Global scope) in domain B.
DomainA\BigGroup contains DomainB\SmallGroup as a sub-group. And DomainB\SmallGroup contains DomainB\User as a member.
Query:
As an Administrator of DomainB, Can we programmatically list all the groups that DomainB\User belongs to?
WindowsIdentity.Groups is not enumerating DomainA\BiggerGroup. Is there any way we can list all the groups that a user belongs to (including the groups in the trusted domains)?
(WindowsIdentity Class has Group property which "Gets the groups the current Windows user belongs to." - http://msdn.microsoft.com/en-us/library/system.security.principal.windowsidentity(v=vs.110).aspx)
As you are working with two domains having forest level trust between them. I think that you can try again using WindowsIdentity.Groups, but establishing a connection (principal context) with a Global Catalog (GC) Directory in spite of any other DC directory.
Strictly speaking, a user may have different group list when log on to different domain.
This is because domain-local group is local to group's own domain only (as its name suggest).
In your case:
When DomainB\User log on to DomainA, the group list contains DomainA\BiggerGroup and DomainB\SmallGroup
When DomainB\User log on to DomainB, the group list contains DomainB\SmallGroup
In general, the group list of a user will contains:
Global & universal groups from USER domain (DomainB in your case), plus
Domain-local groups from connected domain
(or COMPUTER domain if you are logging on a computer)
Other well-known groups, like "Authenticated Users", "Everyone"
(can ignore this if you are only interested in AD groups)
So, w.r.t which domain you want to find out the group list of DomainB\User?
Solution:
To get an accurate group list of a user (without providing password of that user), you can make use of the S4U Kerberos Extensions. (See the S4U2Self section in link below)
http://msdn.microsoft.com/en-us/magazine/cc188757.aspx
The link suggest to use WindowsIdentity. But the WindowsIdentity solution has one problem.
// parameter must be in upn format
WindowsIdentity identity = new WindowsIdentity("User#DomainB.com");
The problem is you cannot control from which domain to get the domain-local groups.
e.g. On computer joined to DomainA, log on as user in DomainB, get WindowsIdentity for user in DomainC. It will get domain-local groups from Domain A, B or C?
Or you may use the LsaLogonUser Win32 function as mentioned in the link. But it takes 14 parameters...
I never tried that before, can't comment on this.
You need to get the token groups for the user. It will return all effective gorup memberships both direct and indirect due to nesting including other domains.
// this method will return all groups where the the user is a direct and indirect member of
public static bool getTokenGroups(string domainFQDN, string alias, ref List<string> userGroups)
{
bool result = false;
try
{
SearchResult sr = default(SearchResult);
using (DirectoryEntry domainDE = new DirectoryEntry("LDAP://" + domainFQDN, "domain\\cn", "password", AuthenticationTypes.Secure))
{
using (DirectorySearcher searcher = new DirectorySearcher(domainDE))
{
searcher.Filter = String.Format("(&(objectClass=user)(sAMAccountName={0}))", alias);
sr = searcher.FindOne();
if (sr != null)
{
using (DirectoryEntry user = sr.GetDirectoryEntry())
{
user.RefreshCache(new string[] { "tokenGroups" });
for (int i = 0; i < user.Properties["tokenGroups"].Count; i++)
{
SecurityIdentifier sid = new SecurityIdentifier((byte[])user.Properties["tokenGroups"][i], 0);
NTAccount nt = (NTAccount)sid.Translate(typeof(NTAccount));
//do something with the SID or name (nt.Value)
if(nt.Value.IndexOf('\\') > -1)
userGroups.Add(nt.Value.Split('\\')[1]);
else
userGroups.Add(nt.Value);
}
}
}
}
}
}
catch (Exception ex)
{
EventLog.WriteEntry("source name", MethodBase.GetCurrentMethod().DeclaringType + "." + MethodBase.GetCurrentMethod().Name + "\r\n\r\nUnable to get user's token groups for domain: " + domainFQDN + " user: " + alias + "\r\n\r\n" + ex.Message, EventLogEntryType.Error);
}
return result;
}
I'm developing an intranet which shows specific links only if a user is member of certain groups in Active Directory.
I'm using this code to effectively check if a user is member of a group. Works fine if the group contains users only, but it doesn't work if there's a group nested in it. What I need is to make it works even if a particular user is in the nested group!
public bool isMember(string user, string group)
{
string value = "";
bool isMember = false;
try
{
DirectoryEntry entry = new DirectoryEntry(domain);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "sAMAccountname=" + user;
SearchResult mySearchResult;
mySearchResult = mySearcher.FindOne();
PropertyValueCollection prop = mySearchResult.GetDirectoryEntry().Properties["memberOf"];
for (int i = 0; i < prop.Count; i++)
{
value = prop[i].ToString();
string[] groups = value.Split(',');
foreach (string property in groups)
{
if (groups[1] == group)
{
isMember = true;
break;
}
}
}
entry.Close();
return isMember;
}
catch (COMException)
{
return false;
}
}
How can I accomplish this?
EDIT :
I've found this code, which allows me to find a user, even if a nested group. The problem is that it works only if my organizational unit contains ONE group, doesn't work if there are more than one...do you think I can edit it a bit to make it work properly??
public bool isMember(string user, string group)
{
bool found = false;
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domain");
GroupPrincipal p = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, group);
UserPrincipal u = UserPrincipal.FindByIdentity(ctx, user);
found = p.GetMembers(true).Contains(u);
p.Dispose();
u.Dispose();
return found;
}
Got this code from ->here<-
You might consider asking AD for their token instead with tokenGroups. Have a look at http://dunnry.com/blog/EnumeratingTokenGroupsTokenGroupsInNET.aspx for a sample.
There are two ways to do this.
Recursively check memberOf property for each group found. Note that there can be circular references so you'll have to keep a track of groups visited to avoid infinite recursion.
Use the LDAP_MATCHING_RULE_IN_CHAIN rule to search for all groups a user belongs to, directly or indirectly. To do this you need to first get the user's DN, then search for groups that contain that userDN as a direct or indirect member. The filter looks something like:
String.Format("(member:1.2.840.113556.1.4.1941:={0})", userDN)
IIRC option 1 is generally faster, but of course needs more code.
I am looking to get a list of all of the groups that a user is a member of in Active Directory, both explicitly listed in the memberOf property list as well as implicitly through nested group membership. For example, if I examine UserA and UserA is a part of GroupA and GroupB, I also want to list GroupC if GroupB is a member of GroupC.
To give you a bit more insight into my application, I will be doing this on a limited basis. Basically, I want a security check occasionally that will list these additional memberships. I will want to differentiate the two but that shouldn't be hard.
My problem is that I have not found an efficient way to make this query work. The standard text on Active Directory (This CodeProject Article) shows a way to do this that is basically a recursive lookup. That seems terribly inefficient. Even in my small domain, a user might have 30+ group memberships. That means 30+ calls to Active Directory for one user.
I've looked into the following LDAP code to get all of the memberOf entries at once:
(memberOf:1.2.840.113556.1.4.1941:={0})
where {0} would be my LDAP path (ex: CN=UserA,OU=Users,DC=foo,DC=org). However, it does not return any records. The downside of this method, even if it worked, would be that I wouldn't know which group was explicit and which was implicit.
That is what I have so far. I would like to know if there is a better way than the CodeProject article and, if so, how that could be accomplished (actual code would be wonderful). I am using .NET 4.0 and C#. My Active Directory is at a Windows 2008 functional level (it isn't R2 yet).
Thirst thanks for this an interesting question.
Next, just a correction, you say :
I've looked into the following LDAP code to get all of the memberOf entries at once:
(memberOf:1.2.840.113556.1.4.1941:={0})
You don't make it work. I remember I make it work when I learnt about its existence, but it was in an LDIFDE.EXE filter. So I apply it to ADSI in C# and it's still working. There were too much parenthesis in the sample I took from Microsoft, but it was working (source in AD Search Filter Syntax).
According to your remark concerning the fact that we don't know if a user explicitly belongs to the group I add one more request. I know this is not very good, but it's the best I'am abable to do.
static void Main(string[] args)
{
/* Connection to Active Directory
*/
DirectoryEntry deBase = new DirectoryEntry("LDAP://WM2008R2ENT:389/dc=dom,dc=fr");
/* To find all the groups that "user1" is a member of :
* Set the base to the groups container DN; for example root DN (dc=dom,dc=fr)
* Set the scope to subtree
* Use the following filter :
* (member:1.2.840.113556.1.4.1941:=cn=user1,cn=users,DC=x)
*/
DirectorySearcher dsLookFor = new DirectorySearcher(deBase);
dsLookFor.Filter = "(member:1.2.840.113556.1.4.1941:=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)";
dsLookFor.SearchScope = SearchScope.Subtree;
dsLookFor.PropertiesToLoad.Add("cn");
SearchResultCollection srcGroups = dsLookFor.FindAll();
/* Just to know if user is explicitly in group
*/
foreach (SearchResult srcGroup in srcGroups)
{
Console.WriteLine("{0}", srcGroup.Path);
foreach (string property in srcGroup.Properties.PropertyNames)
{
Console.WriteLine("\t{0} : {1} ", property, srcGroup.Properties[property][0]);
}
DirectoryEntry aGroup = new DirectoryEntry(srcGroup.Path);
DirectorySearcher dsLookForAMermber = new DirectorySearcher(aGroup);
dsLookForAMermber.Filter = "(member=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)";
dsLookForAMermber.SearchScope = SearchScope.Base;
dsLookForAMermber.PropertiesToLoad.Add("cn");
SearchResultCollection memberInGroup = dsLookForAMermber.FindAll();
Console.WriteLine("Find the user {0}", memberInGroup.Count);
}
Console.ReadLine();
}
In my test tree this give :
LDAP://WM2008R2ENT:389/CN=MonGrpSec,OU=MonOu,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpSec,OU=MonOu,DC=dom,DC=fr
cn : MonGrpSec
Find the user 1
LDAP://WM2008R2ENT:389/CN=MonGrpDis,OU=ForUser1,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpDis,OU=ForUser1,DC=dom,DC=fr
cn : MonGrpDis
Find the user 1
LDAP://WM2008R2ENT:389/CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr
cn : MonGrpPlusSec
Find the user 0
LDAP://WM2008R2ENT:389/CN=MonGrpPlusSecUniv,OU=ForUser1,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpPlusSecUniv,OU=ForUser1,DC=dom,DC=fr
cn : MonGrpPlusSecUniv
Find the user 0
(edited)
'1.2.840.113556.1.4.1941' is not working in W2K3 SP1, it begins to work with SP2. I presume it's the same with W2K3 R2. It's supposed to work on W2K8. I test here with W2K8R2. I'll soon be able to test this on W2K8.
If there is no way other than recursive calls (and I don't believe there is) then at least you can let the framework do the work for you: see the UserPrincipal.GetAuthorizationGroups method (in the System.DirectoryServices.AccountManagement namespace and introduced in .Net 3.5)
This method searches all groups
recursively and returns the groups in
which the user is a member. The
returned set may also include
additional groups that system would
consider the user a member of for
authorization purposes.
Compare with the results of GetGroups ("Returns a collection of group objects that specify the groups of which the current principal is a member") to see whether the membership is explicit or implicit.
Use the ldap filter recursively but query for all groups returned after each query to reduce the number of round trips.
Ex:
Get all groups where user is a member
Get all groups where Step 1 Groups are members
Get all groups where Step 2 Groups are members
...
In my experience there are rarely more then 5 but should definitiely be much less then 30.
Also:
Make sure to only pull the properties
you are going to need back.
Caching results can significantly aid
performance but made my code much
more complicated.
Make sure to utilize connection pooling.
Primary group has to be handled seperately
you can utilize the tokenGroups and tokenGroupsGlobalAndUniversal properties if you are on Exchange server.
tokenGroups will give you all the security groups this user belongs to, including nested groups and domain users, users, etc
tokenGroupsGlobalAndUniversal will include everything from tokenGroups AND distribution groups
private void DoWorkWithUserGroups(string domain, string user)
{
var groupType = "tokenGroupsGlobalAndUniversal"; // use tokenGroups for only security groups
using (var userContext = new PrincipalContext(ContextType.Domain, domain))
{
using (var identity = UserPrincipal.FindByIdentity(userContext, IdentityType.SamAccountName, user))
{
if (identity == null)
return;
var userEntry = identity.GetUnderlyingObject() as DirectoryEntry;
userEntry.RefreshCache(new[] { groupType });
var sids = from byte[] sid in userEntry.Properties[groupType]
select new SecurityIdentifier(sid, 0);
foreach (var sid in sids)
{
using(var groupIdentity = GroupPrincipal.FindByIdentity(userContext, IdentityType.Sid, sid.ToString()))
{
if(groupIdentity == null)
continue; // this group is not in the domain, probably from sidhistory
// extract the info you want from the group
}
}
}
}
}
If you are using .NET 3.5 or higher you can use the System.DirectoryServices.AccountManagement namespace which really makes this easy.
See the related answer here: Active Directory nested groups
static List<SearchResult> ad_find_all_members(string a_sSearchRoot, string a_sGroupDN, string[] a_asPropsToLoad)
{
using (DirectoryEntry de = new DirectoryEntry(a_sSearchRoot))
return ad_find_all_members(de, a_sGroupDN, a_asPropsToLoad);
}
static List<SearchResult> ad_find_all_members(DirectoryEntry a_SearchRoot, string a_sGroupDN, string[] a_asPropsToLoad)
{
string sDN = "distinguishedName";
string sOC = "objectClass";
string sOC_GROUP = "group";
string[] asPropsToLoad = a_asPropsToLoad;
Array.Sort<string>(asPropsToLoad);
if (Array.BinarySearch<string>(asPropsToLoad, sDN) < 0)
{
Array.Resize<string>(ref asPropsToLoad, asPropsToLoad.Length+1);
asPropsToLoad[asPropsToLoad.Length-1] = sDN;
}
if (Array.BinarySearch<string>(asPropsToLoad, sOC) < 0)
{
Array.Resize<string>(ref asPropsToLoad, asPropsToLoad.Length+1);
asPropsToLoad[asPropsToLoad.Length-1] = sOC;
}
List<SearchResult> lsr = new List<SearchResult>();
using (DirectorySearcher ds = new DirectorySearcher(a_SearchRoot))
{
ds.Filter = "(&(|(objectClass=group)(objectClass=user))(memberOf=" + a_sGroupDN + "))";
ds.PropertiesToLoad.Clear();
ds.PropertiesToLoad.AddRange(asPropsToLoad);
ds.PageSize = 1000;
ds.SizeLimit = 0;
foreach (SearchResult sr in ds.FindAll())
lsr.Add(sr);
}
for(int i=0;i<lsr.Count;i++)
if (lsr[i].Properties.Contains(sOC) && lsr[i].Properties[sOC].Contains(sOC_GROUP))
lsr.AddRange(ad_find_all_members(a_SearchRoot, (string)lsr[i].Properties[sDN][0], asPropsToLoad));
return lsr;
}
static void Main(string[] args)
{
foreach (var sr in ad_find_all_members("LDAP://DC=your-domain,DC=com", "CN=your-group-name,OU=your-group-ou,DC=your-domain,DC=com", new string[] { "sAMAccountName" }))
Console.WriteLine((string)sr.Properties["distinguishedName"][0] + " : " + (string)sr.Properties["sAMAccountName"][0]);
}
I am trying to do a very simple AD query to see if a computer is in a group. The following code seems intuitive enough but does not work. The LDAPString is a fully distinguised name for the group that the computer referenced by NetBIOSName is a memberOf.
public bool IsComputerInADGroup(String LDAPString, String NetBIOSName)
{
using (DirectoryEntry entry = new DirectoryEntry(String.Format(#"LDAP://{0}", LDAPString)))
using (DirectorySearcher computerSearch = new DirectorySearcher(entry))
{
ComputerSearch.Filter = String.Format("(&(objectCategory=computer)(CN={0}))", NetBIOSName);
SearchResult match = ComputerSearch.FindOne();
if (match != null)
{
return true;
}
}
return false;
}
Can someone please explain why this is incorrect and what the correct/fastest way to to perform this search is.
Thanks
P
Your basic assumption is wrong - a computer (or user) cannot be in a group implying "containment" inside a group; a user or computer is only inside an OU.
A user or computer can be member of any number of groups - but you need to check this against the member property of the group (or the memberOf attribute of the element that is a member of that group).
So the easiest way, really, is to
bind to the object in question
refresh its property cache to get the latest entries in memberOf
enumerate of its memberOf entries and see if the group you're looking for is present
Something like:
public static bool IsAccountMemberOfGroup(string account, string group)
{
bool found = false;
using (DirectoryEntry entry = new DirectoryEntry(account))
{
entry.RefreshCache(new string[] { "memberOf" });
foreach (string memberOf in entry.Properties["memberOf"])
{
if (string.Compare(memberOf, group, true) == 0)
{
found = true;
break;
}
}
}
return found;
}
Call this like so:
bool isMemberOf =
IsAccountMemberOfGroup("LDAP://cn=YourComputer,dc=Corp,dc=com",
"CN=yourGroupInQuestion,OU=SomeOU,dc=corp,dc=com");
and you should be fine.
Update: if you're on .NET 3.5, you could also use the new System.DirectoryServices.AccountManagement namespace and LINQ to make things even easier:
public static bool IsAccountMemberOfGroup2(PrincipalContext ctx, string account, string groupName)
{
bool found = false;
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, groupName);
if (group != null)
{
found = group.GetMembers()
.Any(m => string.Compare(m.DistinguishedName, account, true) == 0);
}
return found;
}
and call this:
// establish default domain context
PrincipalContext domain = new PrincipalContext(ContextType.Domain);
// call your function
bool isMemberOf =
IsAccountMemberOfGroup2(domain,
"cn=YourComputer,dc=Corp,dc=com",
"CN=yourGroupInQuestion,OU=SomeOU,dc=corp,dc=com");
when you say it doesn't work, you mean that you can't find the computer? If so, check first if the computer is in the group, there is a nice tool out there named Active directory exporer wich can help you: http://technet.microsoft.com/en-us/sysinternals/bb963907.aspx
If it is in the group what you can try is to eliminate the filter for the computer name on the filter and iterate over the resultset in order to find out if your element is there:
ComputerSearch.Filter = ("(&(objectCategory=computer))";
SearchResult match = ComputerSearch.FindAll();
Here's some infos on how to query AD : http://www.codeproject.com/KB/system/everythingInAD.aspx