Dynamics AX in the Field

Microsoft Dynamics AX from the Premier Field Engineering team at Microsoft.

Comparing AX and Active Directory User Accounts

Comparing AX and Active Directory User Accounts

  • Comments 3

I was recently working with an AX 2009 customer who wanted to compare the user accounts configured in AX with the user accounts in Active Directory. The basic goals were:

  1. Find all AX user accounts that no longer exist in Active Directory.
  2. Find all accounts that are disabled in Active Directory but not in AX.

It would be great if AX would flag these scenarios for you, but unfortunately it doesn't. If you’re interested in knowing if you have any orphaned accounts or accounts that should probably be disabled in AX, here’s a quick way to do just that.

  1. Export AD users to a CSV file. I used a PowerShell command for this step. The command I used requires the Active Directory Module for Windows PowerShell. This is installed by default on domain controllers, but it is also available via the Remote Server Administration Tools for Windows 7 if you want to run it from a workstation instead. http://www.microsoft.com/download/en/details.aspx?id=7887
  2. Create a table for the AD user details. I created a new table in the AX database to store the AD user account details so I could easily join this information to the AX user details already stored in the database.
  3. Load the contents of the CSV file into the table. I used a bulk insert statement to load the data from the CSV file created in step 1 into the table created in step 2.
  4. Query the table for your results. I used 2 simple queries that joined the AD user account table with the AX userinfo table to get the information I needed.

NOTE: See the attached text file for the exact PowerShell commands and SQL statements I used.

In the one real world scenario (AX 2009) that we looked at, AX had 112 orphaned accounts and there were another 75 accounts that were disabled in AD but not in AX.

This procedure should work for both AX 4.0 and 2009. The userinfo table still exists in AX 2012, so the comparison should work with this version too, but there might be some scenarios such as flexible authentication that throw the results off. That's something I haven't really looked into yet.

Attachment: Compare_User_Accounts.txt
  • This is nice but a way too complex. Here's a sample job that does the same:

    #define.UserAccountControl  ('userFlags')

    #define.UF_ACCOUNTDISABLE   (0x0002)

    Counter                     numTotal;

    Counter                     numNotFound;

    Counter                     numDisabled;

    UserInfo                    userInfo;

    int                         userAccControl;

    COM                         dirObject;

    str                         dirPath;

    ;

    while select userInfo

       where   userInfo.networkAlias

           &&  userInfo.networkDomain

    {

       numTotal++;

       dirPath = strfmt(@"WinNT://%1/%2,User", userInfo.networkDomain, userInfo.networkAlias);

       dirObject = COM::getObjectEx(dirPath);

       if (dirObject)

       {

           if (userInfo.enable)

           {

               userAccControl = dirObject.get(#UserAccountControl);

               if (bitTest(userAccControl, #UF_ACCOUNTDISABLE))

               {

                   numDisabled++;

                   info(strfmt("%1@%2 disabled in AD, but not in AX", userInfo.networkAlias, userInfo.networkDomain));

               }

           }

           dirObject.finalize();

           dirObject = null;

       }

       else

       {

           numNotFound++;

           warning(strfmt(@"%1@%2 - not found", userInfo.networkAlias, userInfo.networkDomain));

       }

    }

    info(strfmt(@"Total: %1, not found: %2, disabled in AD, but not in AX: %3", numTotal, numNotFound, numDisabled));

  • Dynamics Ax has built in classes for that kind of queries.

    Use class 'xAxaptaUserManager' and class 'xAxaptaUserDetails' for this.  A simple query of the users and calling these classes to get the details does the trick.  No need to complicate things.

    dynamics-ax-live.blogspot.com

  • Wrote once a Job to update the SID after a Domain change, but you could also use it to Sync the active accounts between AD and AX

    static void ChangeDomain(Args _args)

    {

       UserInfo                userInfo;

       xAxaptaUserManager      axUsrMgr;

       xAxaptaUserDetails      axUsrDet;

       Boolean                 doUpdate;

       Username                             user;

       SID                             oldSID;

       #define.NewDomain("New.DOMAIN.NET")

       ;

        doUpdate = Box::yesNo("User aktualisieren?", DialogButton::No) == DialogButton::Yes;

       axUsrMgr = new xAxaptaUserManager();

       ttsbegin;

       setPrefix('SID-Aktualisierung');

       while select forupdate userInfo

       {

           axUsrDet = axUsrMgr.getDomainUser(#NewDomain,userInfo.networkAlias);

           if(userInfo && axUsrDet)

           {

               oldSID = userInfo.sid;

               userInfo.networkDomain      = #NewDomain;

               userInfo.sid                = axUsrMgr.getUserSid(userInfo.networkAlias, #NewDomain);

               if(doUpdate)

               {

                   info(strfmt("Aktualisiert", userInfo.networkAlias));

                   userInfo.update();

               }

           }

           else

           {

               error(strfmt("Nicht gefunden", userInfo.networkAlias));

           }

       }

       ttscommit;

    }

Page 1 of 1 (3 items)