Link to home
Start Free TrialLog in
Avatar of SuperMario
SuperMario

asked on

Using System.DirectoryServices to enumerate users on the current system.

Hi everyone,
I am trying to use System.DirectoryServices to show a list of Active Directory users on the current machine.

I'm doing something like this:


string sDomain = Environment.UserDomain;
string sMachine = Environment.MachineName;
string sLocalPath = "winnt://" + sDomain + "/" + sMachine; // I think this path is wrong

// the path is something like winnt://domain/machinename
// then I try this:

DirectoryEntry root = new DirectoryEntry(sLocalPath);
root.Children.SchemaFilter.Add("Users");
foreach(DirectoryEntry de in root.Children)
{
   // enumerate the users.
}

However, it keeps throwing a darned exception on this line:
root.Children.SchemaFilter.Add("Users");

Anybody have any idea, or maybe another way using DirectoryServices to get a list of users on the local box? I already have it getting a list from the highest level, which is not what I want.

Thank you,
-Dan Waters
Avatar of naveenkohli
naveenkohli

Check this out..

http://www.netomatix.com/DirectoryServices.aspx

It has whole bunch os samples on enumerating users, groups etc. Some are using LDAP provider, but can replace it with WinNT provider.
Avatar of SuperMario

ASKER

I hate to tell you this, but I've seen that link before and I really need some personal assistance... Thank you though.

For example, I want to find a list of local groups on the machine... Why won't my code I posted work? besides the fact that I put users as the filter.

I keep getting exceptions.

Any ideas?

Thanks,
Dan
Fair enough...
One problem.. Since you are trying to get local groups, then there is no point of specifying domain in the query path.

string sLocalPath = "winnt://" + sMachine

Try this.. and let mw know.
The other issue which is big trouble... WinNT provider does not have a concept of schema filters. It is used by LDAP/AD. So you will have to enumerate through the children list and filter out the objects of type "User"
See if the following code does the job for you..

using System;
using System.DirectoryServices;

namespace ADSISample
{
      /// <summary>
      /// Summary description for Class1.
      /// </summary>
      class Class1
      {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main(string[] args)
            {
                  string sMachine = Environment.MachineName;
                  string sLocalPath = "WinNT://" + sMachine;

                  DirectoryEntry root = new DirectoryEntry(sLocalPath);
                  int idx = 0;
                  foreach(DirectoryEntry de in root.Children)
                  {
                        if (de.SchemaClassName.CompareTo("User") == 0)
                        {
                              Console.WriteLine("This is my user {0}", idx);
                              Console.WriteLine("*************************");
                              foreach (string propName in de.Properties.PropertyNames)
                              {
                                    foreach (object value in de.Properties[propName] )
                                    {
                                          Console.WriteLine("Prop Name=" + propName + "  Value=" + value);
                                    }
                              }
                        }
                        else
                        {
                              Console.WriteLine(de.SchemaClassName);
                        }
                  }
            }
      }
}
I ended up solving it with DirectorySearcher. It turns out winnt is case sensitive and actually has to be WinNT...

But, for the points, here's another one:

Do you happen to know how I can add a user to a group? I know basically how to do it, setting the "Members" property of a group, but I am having a problem with the security. I think this has to do with Impersonation.

Mind you, I am not doing this with ASP.NET (where it's very easy to impersonate), but rather on a regular C# application.

If you could give me some guidance I'd be VERY thankful!

Thanks, and sorry I keep jumping around...
-Dan W.
ASKER CERTIFIED SOLUTION
Avatar of naveenkohli
naveenkohli

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Okay, I have one more question, and after that I'll reward the points (I've raised them to 120).

I am trying to add a DOMAIN user to a LOCAL group.

My group path is something like:

WinNT://MACHINENAME/GROUPNAME

The user path is like this:

WinNT://DOMAIN/USERNAME

Both the user and group DirectoryEntry objects exist... But when I try to invoke an Add method on the Group object, it throws a COMException saying the username is invalid.

This code was working fine before, I have just changed some paths.

Any suggestions?
thanks again for your help!
-Dan
Post the code..
                               /// <summary>
            /// Adds a domain user to a local group.
            /// </summary>
            /// <param name="sDomain">The domain in which the user is found.</param>
            /// <param name="sUser">The username.</param>
            /// <param name="sGroup">Group name.</param>
            /// <returns></returns>
            public bool addDomainUserToLocalGroup(string sDomain, string sUser, string sGroup)
            {
                  // Perform some basic error handling on parameters.
                  if(sGroup == "" || sGroup == null)
                        return error("Invalid group name.", true);
                  if(sUser == "" || sUser == null)
                        return error("Invalid user name.", true);
                  if(sMachine == "" || sMachine == null)
                        return error("Invalid machine name.", true);

                  string userPath, groupPath;
                  if(sDomain != "" && sDomain != null)
                  {
                        userPath = "WinNT://" + sDomain + "/" + sUser;
                        groupPath = "WinNT://" + this.sMachine + "/" + sGroup;
                  }
                  else
                        return error("The domain was not specified.", true);

                  try
                  {
                        DirectoryEntry group      = new DirectoryEntry(groupPath, this.AuthUser, this.AuthPassword);
                        DirectoryEntry user            = new DirectoryEntry(userPath, this.AuthUser, this.AuthPassword);

                        if(!dirExists(group.Path))
                              return error("Group " + sGroup + " does not exist. Path: " + group.Path, true);
                        if(!dirExists(user.Path))
                              return error("User " + sUser + " does not exist. Path: " + user.Path, true);
                        
                        bool isMember = (bool)group.Invoke("isMember", new object[] { userPath });
                        //bool isMember = false;

                        // If the user is not a member of the specified group already...
                        if(!isMember)
                        {
                              // Go ahead and invoke the Add method and commit changes.
                              group.Invoke("add", new object[] { userPath } );
                              group.CommitChanges();
                        }
                        else
                              // Otherwise, flag an error (the user already exists in that group.)
                              return error("User " + sUser + " is already a member of " + sGroup + ". User Path=" + user.Path + ", Group Path=" + group.Path, false);
                  }

                  catch(System.Runtime.InteropServices.COMException ce)
                  {
                        //return exceptionError(ce);
                        return error("Group path: " + groupPath + ", User path: " + userPath, true);
                  }
                  catch(Exception ex)
                  {
                        return exceptionError(ex);
                  }

                  return true;
            }
By the way, it also throws on the Invoke isMember method.

-Dan
Hell, I got it to work, imagine that...

When you login, you have to login as DOMAIN\user with a backslash.

Any paths you reference must all have forward slashes.

Wow!

Here you go... :)