I am trying to determine if a given local user account is in the local Administrators group. Everything works fine until the system is joined to a domain. When joined to a domain an exception is thrown that the network path was not found, but only when looking for local non-Administrator accounts; if the test account is local Admin, the method returns fine.
This is an example of the code:
string accountName = @"localAccountName";
string groupName = @"Administrators";
using (PrincipalContext principalContext = new PrincipalContext(ContextType.Machine))
{
using (UserPrincipal accountPrinciple = new UserPrincipal(principalContext))
{
accountPrinciple.SamAccountName = accountName;
using (PrincipalSearcher accountSearcher = new PrincipalSearcher(accountPrinciple))
{
UserPrincipal account = (UserPrincipal)accountSearcher.FindOne();
if(account != null)
{
using (GroupPrincipal groupPrinciple = new GroupPrincipal(principalContext))
{
groupPrinciple.SamAccountName = groupName;
using (PrincipalSearcher groupSearcher = new PrincipalSearcher(groupPrinciple))
{
GroupPrincipal group = (GroupPrincipal)groupSearcher.FindOne();
if (account.IsMemberOf(group))
{
Console.WriteLine(@"{0} is part of the administrators group", accountName);
}
else
{
Console.WriteLine(@"{0} is not part of the administrators group", accountName);
}
}
}
}
else
{
Console.WriteLine(@"{0} is not found", accountName);
}
}
}
}
The resulting stack is:
Unhandled Exception: System.Runtime.InteropServices.COMException: The network path was not found.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.PropertyValueCollection.PopulateList()
at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
at System.DirectoryServices.PropertyCollection.get_Item(String propertyName)
at System.DirectoryServices.AccountManagement.SAMStoreCtx.ResolveCrossStoreRefToPrincipal(Object o)
at System.DirectoryServices.AccountManagement.SAMMembersSet.MoveNextForeign()
at System.DirectoryServices.AccountManagement.SAMMembersSet.MoveNext()
at System.DirectoryServices.AccountManagement.PrincipalCollectionEnumerator.MoveNext()
at System.DirectoryServices.AccountManagement.PrincipalCollection.ContainsEnumTest(Principal principal)
at AdminGroupTest.Program.Main(String[] args)
I've specified the machine context and tried using the overloads to further specify the local machine. I could understand if it was a permissions issue with the AD, except simply changing the target account changes the behavior regardless of the executing account, and querying a local administrator account (not default admin) works. The PrincipleSearcher finds the account, but can't test membership... There must be something I am overlooking.
By default when joining a computer to a domain, the "Domain Admins" group will be added to the local "Administrators" group.
When you query to Principal.IsMemberOf(GroupPrincipal), the GroupPrincipal.Members are enumerated.
First, all of the top level group members are checked. This includes local users, which is why the call succeeds when checking for a local administrator user.
If no matches are found, then the code enumerates other groups which are members of the group in question. In this case, Domain Admins.
In order to enumerate the members of Domain Admins, an active directory lookup is required, but your executing user does not have privileges to execute the domain query.
Rather than enumerating groups to look for members, you can simply ask the UserPrincipal for its groups:
string accountName = @"localAccountName";
string groupName = @"Administrators";
using (PrincipalContext principalContext = new PrincipalContext(ContextType.Machine))
{
using (UserPrincipal accountPrinciple = new UserPrincipal(principalContext))
{
accountPrinciple.SamAccountName = accountName;
using (PrincipalSearcher accountSearcher = new PrincipalSearcher(accountPrinciple))
{
UserPrincipal account = (UserPrincipal)accountSearcher.FindOne();
if (account != null)
{
foreach (var group in account.GetGroups())
{
if (group.SamAccountName == groupName && group.ContextType == ContextType.Machine)
{
Console.WriteLine(@"{0} is part of the administrators group", accountName);
return;
}
}
Console.WriteLine(@"{0} is not part of the administrators group", accountName);
}
else
{
Console.WriteLine(@"{0} is not found", accountName);
}
}
}
}