MikeBaz - MSFT
MikeBaz - MSFT

Reputation: 3238

Delay in Active Directory user creation when using System.DirectoryServices.AccountManagement

I am creating accounts and setting properties on them using System.DirectoryServices.AccountManagement in .NET 4.5. One of the requirements is that the group membership (including Primary Group) be copied from a template account. The code includes the following:

foreach (var group in userPrincipal.GetGroups()) {
    var groupPrincipal = (GroupPrincipal) @group;

    if (groupPrincipal.Sid != templatePrimaryGroup.Sid) {
        groupPrincipal.Members.Remove(userPrincipal);
        groupPrincipal.Save();
    }
}

This works about 90% of the time. The rest of the time, it fails with:

System.DirectoryServices.DirectoryServicesCOMException was unhandled HResult=-2147016656 Message=There is no such object on the server.

Source=System.DirectoryServices ErrorCode=-2147016656 ExtendedError=8333 ExtendedErrorMessage=0000208D: NameErr: DSID-03100213, problem 2001 (NO_OBJECT), data 0, best match of: 'OU=Whatever,DC=domain,DC=local`

on the GetGroups call. My guess is that there is a race condition of some sort with the user not being fully created before I next go to access it. I know from diagnostic logging that I am going against the same domain controller each time (it's using the same PrincipalContext so that matches my expectation) so it's not a replication issue.

Is my guess accurate? Is there a good way to handle this? I could just throw in a Sleep but that seems like a cop-out at best and fragile at worst. So what is the right thing to do?

Upvotes: 2

Views: 2151

Answers (1)

Daro
Daro

Reputation: 2010

Try something like:

        int maxWait = 120;
        int cnt = 0;
        bool usable = false;

        while (usable == false && cnt < maxWait)
        {
            try
            {
                foreach (var group in userPrincipal.GetGroups())
                {
                    var groupPrincipal = (GroupPrincipal)@group;

                    if (groupPrincipal.Sid != templatePrimaryGroup.Sid)
                    {
                        groupPrincipal.Members.Remove(userPrincipal);
                        groupPrincipal.Save();
                    }
                }
                usable = true;
                break;
            }
            catch
            {
                System.Threading.Thread.Sleep(500);
            }
        }
        if (usable)
            //All okay
            ;
        else
            //Do something
            ;

This way you can try for "a while". If it works good, if not do something like log an error, so you can run a fix-it script later.

Upvotes: 1

Related Questions