DirectoryServices: what's wrong with my COM interop?

N

Natalia DeBow

Hi,

In my app, I need to check if the current user is a member of the
Administrators group in order to allow/deny some action.

I read some posts from Willy Denoyette (VIP) where he actually posted some
code how to get the group membership for a given user.

I am using System.DirectoryServices namespace provided by .NET Framework 1.1
with the implementation language being C#.

Here is the code that is generating a null pointer exception to be thrown:
using System.DirectoryServices; ///<remarks> User Account Info </remarks>

using System.Runtime.InteropServices;

using activedsnet;

..........



private bool verifyCurrentUserAccount()

{

IADsMembers MembersCollection = null;

DirectoryEntry _groupEntry = new DirectoryEntry("WinNT://" +

Environment.MachineName + ",computer");

try

{

// call native method "members" on the IADsGroup COM interface exposed by
activeds.dll

IADsGroup gr = _groupEntry.NativeObject as IADsGroup;

MembersCollection = gr.Members(); *** --> gr is NULL here, thus
causing a null pointer exception to be thrown. ***

// or call Invoke on the DirectoryEntry object passing the Method to call as
arg.

// cast the retruned object to IADsMembers

// MembersCollection = _groupEntry.Invoke("Members") as IADsMembers;

object[] filter = {"user"};

MembersCollection.Filter = filter;

// enumerate members of collection object that supports the IADsMembers
interface

// ADSI provider doesn't support count property!!

try

{

foreach (IADsUser member in MembersCollection)

{

System.Console.WriteLine("[{0}]", member.Name);

ListUserProp(member.ADsPath);

}

}

catch (Exception e)

{

System.Console.WriteLine("Error: {0}",e.Message);

}

}

catch (Exception e)

{

System.Console.WriteLine(e.Message);

}

finally

{

_groupEntry.Dispose();

}

return true;

}



private static void ListUserProp(string dirPath)

{

DirectoryEntry userEntry = null;

try

{

userEntry = new DirectoryEntry(dirPath);

PropertyCollection pcoll = userEntry.Properties;

foreach(string sc in pcoll.PropertyNames)

System.Console.WriteLine("\t" + sc + "\t" + pcoll[sc].Value);

}

catch (Exception e)

{

System.Console.WriteLine(e.Message);

}

finally

{

userEntry.Dispose();

}

}

I added a reference to activedsnet.dll for the project, so I don't think
that's the issue.

It seems like my activedsnet.dll is not working, but I verified if all the
interfaces were generated. I had to run TlbImp.exe tool on activeds.tlb to
generate my activedsnet.dll. The TlbImp generated a lot of warnings, but no
errors. I am not sure if that's the problem or if there is some other issue
that causes my code to blow up.



Any comments/suggestions are greatly appreciated.



Thanks,

Natalia
 
W

Willy Denoyette [MVP]

If you know the name of the group, you better start from the group itself:

// call site
ListUsersInGroup("administrators");

.....
private static void ListUsersInGroup(string GroupName) {
IADsMembers MembersCollection = null;
using(DirectoryEntry groupEntry = new DirectoryEntry("WinNT://" +
Environment.MachineName + "/" + GroupName + ",group"))
{
// invoke native method "members"
MembersCollection = groupEntry.Invoke("Members") as IADsMembers;
object[] filter = {"User"};
MembersCollection.Filter = filter;
foreach (IADsUser user in MembersCollection)
{
Console.WriteLine("User Name: " + user.Name );
}
}
}


Also beware that searching group membership using the WinNT provider is
expensive in terms of resources and not really performant. So caching might
be needed.
Willy.

Natalia DeBow said:
Hi,

In my app, I need to check if the current user is a member of the
Administrators group in order to allow/deny some action.

I read some posts from Willy Denoyette (VIP) where he actually posted some
code how to get the group membership for a given user.

I am using System.DirectoryServices namespace provided by .NET Framework
1.1
with the implementation language being C#.

Here is the code that is generating a null pointer exception to be thrown:
using System.DirectoryServices; ///<remarks> User Account Info </remarks>

using System.Runtime.InteropServices;

using activedsnet;

.........



private bool verifyCurrentUserAccount()

{

IADsMembers MembersCollection = null;

DirectoryEntry _groupEntry = new DirectoryEntry("WinNT://" +

Environment.MachineName + ",computer");

try

{

// call native method "members" on the IADsGroup COM interface exposed by
activeds.dll

IADsGroup gr = _groupEntry.NativeObject as IADsGroup;

MembersCollection = gr.Members(); *** --> gr is NULL here, thus
causing a null pointer exception to be thrown. ***

// or call Invoke on the DirectoryEntry object passing the Method to call
as
arg.

// cast the retruned object to IADsMembers

// MembersCollection = _groupEntry.Invoke("Members") as IADsMembers;

object[] filter = {"user"};

MembersCollection.Filter = filter;

// enumerate members of collection object that supports the IADsMembers
interface

// ADSI provider doesn't support count property!!

try

{

foreach (IADsUser member in MembersCollection)

{

System.Console.WriteLine("[{0}]", member.Name);

ListUserProp(member.ADsPath);

}

}

catch (Exception e)

{

System.Console.WriteLine("Error: {0}",e.Message);

}

}

catch (Exception e)

{

System.Console.WriteLine(e.Message);

}

finally

{

_groupEntry.Dispose();

}

return true;

}



private static void ListUserProp(string dirPath)

{

DirectoryEntry userEntry = null;

try

{

userEntry = new DirectoryEntry(dirPath);

PropertyCollection pcoll = userEntry.Properties;

foreach(string sc in pcoll.PropertyNames)

System.Console.WriteLine("\t" + sc + "\t" + pcoll[sc].Value);

}

catch (Exception e)

{

System.Console.WriteLine(e.Message);

}

finally

{

userEntry.Dispose();

}

}

I added a reference to activedsnet.dll for the project, so I don't think
that's the issue.

It seems like my activedsnet.dll is not working, but I verified if all the
interfaces were generated. I had to run TlbImp.exe tool on activeds.tlb
to
generate my activedsnet.dll. The TlbImp generated a lot of warnings, but
no
errors. I am not sure if that's the problem or if there is some other
issue
that causes my code to blow up.



Any comments/suggestions are greatly appreciated.



Thanks,

Natalia
 
M

Marc Scheuner [MVP ADSI]

Hi Natalia,
In my app, I need to check if the current user is a member of the
Administrators group in order to allow/deny some action.

Is there any particular reason why you start using the nice S.DS
namespace, and then go back to the "old-style", messy IADs
interfaces??

Unless you have some very specific reason for it, I'd stick to using
S.DS all the way - it's MUCH nicer and easier to use!

Also, another point: why do you use the WinNT provider?? That provider
is old, deprecated, and really only provided for backwards
compatibility with NT4 systems. if ever possible, AVOID it at all
costs - use LDAP instead.

To check if a given user is member of the "Administrators" group,
you'll need to

a) know your user's LDAP path
b) know your "Administrators" LDAP path

Given those two, you can easily detect this condition in S.DS

// set up the strings - user needs to be the fully qualified LDAP path
// including the LDAP:// provider prefix, while the "Administrators"
// string needs to be just the DN (distinguishedName) of the group

string sUser = "LDAP://cn=Natalia,ou=SomeOU,dc=yourcompany,dc=com";
string sAdmGrp = "cn=Administrators,cn=Builtin,dc=yourcompany,dc=com";

// bind to the user
DirectoryEntry deUser = new DirectoryEntry(sUser);

// enumerate it's "member" strings to see if it's
/ member of "Administrators"
bool bIsMemberOfAdmin = false;

foreach(object oGrp in deUser.Properties["member"])
{
if(oGrp.ToString() == sAdmGrp)
{
bIsMemberOfAdmin = true;
break;
}
}

if(bIsMemberOfAdmin)
// ..... do one thing
else
// do something else


Marc


================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top