So I have this string:
testvm\Administrator
Where my machine hostname is 'testvm' and I call FindByIdentity using the domain context with that name. The problem is that FindByIdentity is returning the domain Administrator account (I know because it has a non-null UPN of that domain account and local accounts can't have a UPN). So why is it ignoring the hostname part of of the string? Shouldn't FindByIdentity return null because I'm specifically putting that machine hostname in there? Here is my code:
private bool GetPrincipalFromName_IsDomain(string sName, out Principal userPrincipal)
{
bool bIsDomain = false;
userPrincipal = null;
PrincipalContext pcontextDomain = null;
try
{
pcontextDomain = new PrincipalContext(ContextType.Domain);
}
catch (Exception ex)
{
throw new Exception("Unable to Initialize Domain Context", ex);
}
try
{
userPrincipal = Principal.FindByIdentity(pcontextDomain, sName);
if(userPrincipal != null)
{
bIsDomain = true;
}
}
catch(MultipleMatchesException mmEx)
{
throw new Exception(string.Format("Found more than one Principal on Domain using Name '{0}'. Use a more precise domain name.", sName), mmEx);
}
catch (Exception ex)
{
throw new Exception(string.Format("Unable to Find Principal on Domain using Name '{0}'.", sName), ex);
}
return bIsDomain;
}
The only workaround I can find is to pass in:
testvm\\Administrator
Then FindByIdentity returns null in the domain context and non-null if I call it with the the local context. Why?
OK things I didn't fully grasp:
The PrincipalContext constructor with the domain context assumes the local domain. If you do not want to assume a domain, you have to tell it explicitly which one in the next argument. In the case of the machine context, you have to let it assume the local machine OR specify which machine you want in the next argument.
That FindByIdentity method cares nothing about anything before the slash. FindByIdentity looks for a type of identity (IdentityReference) and defaults to 'Name' which is a user or group name. It expects the name of the user or group unless you specify a different type of identity like SID, in which case it looks for the Principal in that context. So in my case of 'domain\jlaird' it was ignoring everything before the slash and looking up 'jlaird' in the current domain (I guess the domain the process was running under).
So I needed some way to take a account string like 'DOMAIN_OR_MACHINE\USER_OR_GROUP' and get a Principal object out of it. Solution...
If the SID is not NULL, I can assume the account string is OK (it exists). So then...
Then I have a user or group: a) Account string in the format of 'DOMAIN_OR_MACHINE\USER_OR_GROUP' that is valid. b) I know whether it is domain (and part of the specified domain) or that it belongs to the machine c) I know whether it is a user or group by looking at the Principal object.
So that solved the problem for me. Messy, and I think Microsoft made this process a PITA but it works.
If this is useful to someone else, please mark as an answer.