When using the new System.DirectoryServices.AccountManagement namespace, one might be inclined (as was I) to use the following code to add a user to a group (exception and comments handling removed):
using (GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity( domainContext, System.DirectoryServices.AccountManagement.IdentityType.Name, groupName)) { if (groupPrincipal != null) { using (UserPrincipal userPrincipal = UserPrincipal.FindByIdentity( domainContext, System.DirectoryServices.AccountManagement.IdentityType.UserPrincipalName, UPN)) { if (userPrincipal != null) { groupPrincipal.GroupScope = GroupScope.Global; groupPrincipal.Members.Add(userPrincipal); groupPrincipal.Save(); } } } }
This works just fine if your machine is joined to the domain you’re trying to provision. However, if your machine is not joined, the groupPrincipal.Save(); call throws a PrincipalException with an error code 1355 (“Information about the domain could not be retrieved (1355)”).
Joining the domain solves this issue.
So what if joining the domain isn’t an option?
In this case I found resorting to good old System.DirectoryServices fixes the issue, using the following code fragment:
using (UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(domainContext, UPN)) { if (userPrincipal != null) { using (GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, groupName)) { if (groupPrincipal != null) { if (!userPrincipal.IsMemberOf(groupPrincipal)) { string userSid = string.Format("<SID={0}>", ((DirectoryEntry)userPrincipal.GetUnderlyingObject()).ToSidString()); DirectoryEntry groupDirectoryEntry = (DirectoryEntry)groupPrincipal.GetUnderlyingObject(); groupDirectoryEntry.Properties["member"].Add(userSid); groupDirectoryEntry.CommitChanges(); } } } } }
ToSidString is an extension method which translates the “objectSid” property:
public static string ToSidString(this DirectoryEntry entry) { StringBuilder sb = new StringBuilder(); foreach (byte b in (byte[])entry.Properties["objectSid"].Value) { sb.Append(b.ToString("X2")); } return sb.ToString(); }
HTH!