Question

I'm trying to list all the groups that a given user belongs to, and I want to support both local machine accounts and domain accounts. I can get the groups for domain accounts with the following code:

public void ListAllGroupsDomain()
{
    ListAllGroups(ContextType.Domain,
                  "myDomain",
                  "myDomainUser",
                  "myDomainPassword");
}

public void ListAllGroups(ContextType contextType
                          string name,
                          string username,
                          string password)
{
    using (var context = new PrincipalContext(contextType,
                                              name,
                                              username,
                                              password))
    {
        using (var findByIdentity = UserPrincipal.FindByIdentity(context, "testedit"))
        {
            if (findByIdentity != null)
            {
                var groups = findByIdentity.GetGroups(context);
                var results = groups.Select(g => g.Name).ToArray();
                Console.WriteLine("Listing {0} groups", results.Count());
                foreach (var name in results)
                {
                    Console.WriteLine("{0}", name);
                }
            }
        }
    }
}

However, if I try to call for an account local to the machine, I get a COM exception saying that my username or password is incorrect (which they aren't):

public void ListAllGroupsMachine()
{
    ListAllGroups(ContextType.Machine,
                  "myMachine",
                  "myMachineUser",
                  "myMachinePassword");
}

I'm guessing that I'm using the FindByIdentity incorrectly for machine accounts. So I tried a slightly different approach that doesn't use FindByIdentity:

public void ListAllGroups2(ContextType contextType
                          string name,
                          string username,
                          string password)
{
    using (var context = new PrincipalContext(contextType,
                                              name,
                                              username,
                                              password))
    {
        using (var userContext = new UserPrincipal(context))
        {
            var results = userContext.GetGroups();
            Console.WriteLine("Listing {0} groups:", results.Count());
            foreach (var principal in results)
            {
                Console.WriteLine("{0}", principal.Name);
            }
        }
    }
}

This version didn't throw any exceptions, but the call to GetGroups() also didn't return any results. How can I get the groups a particular user belongs to that is reliable for both machine and domain accounts?

Was it helpful?

Solution

Thanks to a little help I gleaned from https://stackoverflow.com/a/3681442/1222122, I figured out what I was doing wrong. I was setting up the PrincipalContext incorrectly. I didn't need to give it the domain, username, or password, just the ContextType. The following code works for both local machine accounts and domain accounts:

public void ListAllGroupsDomain()
{
    ListAllGroups(ContextType.Domain, "myDomainUsername");
}

public void ListAllGroupsMachine()
{
    ListAllGroups(ContextType.Machine, "myMachineUsername");
}

public void ListAllGroups(ContextType contextType, string userName)
{
    using (var context = new PrincipalContext(contextType))
    {
        using (var findByIdentity = UserPrincipal.FindByIdentity(context, userName))
        {
            if (findByIdentity != null)
            {
                var groups = findByIdentity.GetGroups(context);
                var results = groups.Select(g => g.Name).ToArray();
                Console.WriteLine("Listing {0} groups", results.Count());
                foreach (var name in results)
                {
                    Console.WriteLine("{0}", name);
                }
            }
        }
    }
}

The only thing I needed to be sure to do was to strip out the domain from the username before I passed it to ListAllGroups because the function that was providing it to me would prepend it to the username in some cases.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top