"Mark Rae" <ma**@markNOSPAMrae.comwrote in message
news:OH**************@TK2MSFTNGP04.phx.gbl...
"Dave Sexton" <dave@jwa[remove.this]online.comwrote in message
news:uT*************@TK2MSFTNGP02.phx.gbl...
>You'll have to use P/Invoke for this, of course :)
System.DirectoryServices will do all of this, and much more, for you without recourse to
p/invoke...
using System;
using System.Collections.Generic;
using System.DirectoryServices;
public static List<stringGetGroupsForUser(string pstrUser)
{
/// <summary>
/// Gets the groups a user is a member of
/// </summary>
/// <param name="pstrGroup">ActiveDirectory group to evaluate</param>
/// <returns>List<stringof groups for pstrUser</returns>
DirectorySearcher objDS = null;
SearchResult objSR = null;
DirectoryEntry objUser = null;
List<stringlstGroups = new List<string>();
try
{
objDS = new DirectorySearcher("objectCategory=User");
objDS.Filter = "(SAMAccountName=" + pstrUser + ")";
objSR = objDS.FindOne();
objUser = new DirectoryEntry(objSR.Path);
PropertyCollection colProperties = objUser.Properties;
PropertyValueCollection colPropertyValues = colProperties["memberOf"];
foreach (string strGroup in colPropertyValues)
{
lstGroups.Add(GetSAMAccountName(strGroup).ToLower( ));
}
return lstGroups;
}
catch (Exception)
{
throw;
}
finally
{
if (objUser != null)
{
objUser.Close();
objUser.Dispose();
objUser = null;
}
if (objSR != null)
{
objSR = null;
}
if (objDS != null)
{
objDS.Dispose();
objDS = null;
}
}
}
public static string GetSAMAccountName(string pstrPath)
{
/// <summary>
/// Gets a SAM Account Name from a given LDAP path
/// </summary>
/// <param name="pstrPath">LDAP path to bind to</param>
DirectoryEntry objADEntry = null;
try
{
objADEntry = new DirectoryEntry("LDAP://" + pstrPath);
return objADEntry.Properties["SAMAccountName"].Value.ToString();
}
catch (System.Runtime.InteropServices.COMException)
{
return String.Empty;
}
catch (System.NullReferenceException)
{
return String.Empty;
}
catch (Exception)
{
throw;
}
finally
{
if (objADEntry != null)
{
objADEntry.Close();
objADEntry.Dispose();
objADEntry = null;
}
}
}
Just a few remarks:
You may simplify your code and make it easier to read and maintain by applying the *using*
idiom, this way, you get rid of the Dispose, Close and completely redundant "obj = null"
calls.
Your code will only work when the caller is running in his domain account, when this is not
the case, you need to bind explicitly against the Domain or the DC, and preferably using
FastBind for performance reasons. You may also bind to the GC (the Global Catalog) using
GC://... in order to speed-up the queries.
Another point to consider is that the binding user must have "query" privileges to all of
the objects you query, normally all domain member do have this privilege, but highly secured
AD's may restrict access to some objects to special accounts only. So it's possible that a
user can bind to his user object, but not to (some) of the related objects.
You should also try to reuse the already established DirectoryEntry object for further
operations against the AD, the way you do forces adsi to rebind and this can be a costly
operation especially on slow connections and uses a lot more resources at the LDAP server.
The following code snip shows how to take advantage of a single bind by using the
GetDirectorEntry() for each successive object retrieval.
public static List<stringGetGroupsForUser(string userAccount)
{
string rootPath = "LDAP://{0}/DC=xxx,DC=yyy,DC=zzz";
string accountDomain = "domain"; // domain name or dc name or empty when binding to
logon domain
string userAccount = userAccount
rootPath = String.Format(
rootPath
, accountDomain);
string authUser = "xxx\yyyyy"; // account used to bind, here hardcoded, not
production safe!
string authPassword = "PASSWORD"; // his password, here hardcoded, not production
safe!
List<stringlstGroups = new List<string>();
using (DirectoryEntry root = new DirectoryEntry(rootPath, authUser, authPassword,
AuthenticationTypes.FastBind))
{
using (DirectorySearcher ds = new DirectorySearcher(root))
{
SearchResult sr = null;
ds.Filter = "(SAMAccountName=" + userAccount + ")";
sr = ds.FindOne();
using (DirectoryEntry user = sr.GetDirectoryEntry())
{
PropertyCollection pcoll = user.Properties;
PropertyValueCollection memberOf = pcoll["memberOf"];
foreach (string cnGroup in memberOf)
{
ds.Filter = cnGroup.Substring(0, cnGroup.IndexOf(','));
sr = ds.FindOne();
using (DirectoryEntry group = sr.GetDirectoryEntry())
{
lstGroups.Add(group.Properties["SAMAccountName"].Value.ToString());
}
}
}
}
}
return lstGroups;
}
....
Willy.