Skip to main content

Comparing AX and Active Directory User Accounts

metod 1

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.

===========
metod 2

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));

========

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;
}

Popular posts from this blog

What does this mean: "The form datasource query object does not support changing its AllowCrossCompany property after the form has executed the query."?

I have made a form with datasources vendtable and vendtrans. Inside vendtable_ds.executequery() looks like this: QueryBuildDataSource queryBuildDatasource ,queryBDS_VendTrans_Invoice; ; queryBuildDatasource = this.query().dataSourceTable(tablenum(vendtable)); queryBDS_VendTrans_Invoice = this.query().dataSourceTable(tablenum(vendtrans)); if (curext() == "MASTERCOMP") { this.query().allowCrossCompany(true); } else { this.query().allowCrossCompany(false); } //FilterVendorName = stringedit control on form if (FilterVendorName.text()) { queryBuildDatasource.addRange(fieldNum(VendTable,Name)).value(strfmt("*%1*", FilterVendorName.text())); } else { queryBuildDatasource.clearRange(fieldNum(VendTable,Name)); } //FilterInvoiceNumber = stringedit control on form if (FilterInvoiceNumber.valueStr() == "") { queryBDS_VendTrans_Invoice.enabled(false); } else { queryBDS_VendTrans_Invoice.enabled(true); queryBDS_VendTrans_In...

Credit Note [Dynamics AX] using X++

This post will help to create credit note for a sales order based on the invent lot id. All the invoices raised for a particular sales line – Lot Id will be raised back as a credit note. Information on Credit Note: A credit note or credit memorandum (memo) is a commercial document issued by a seller to a buyer. The seller usually issues a Credit Memo for the same or lower amount than the invoice, and then repays the money to the buyer or sets it off against a balance due from other transactions Below Code will help to create credit note for all the invoices raised against the sales line -lot id. Please note: This code can be customized as per your requirements. This is just a template to help creating credit note using X++ code. Please test the code before use. static void SR_CreateCreditNote_Sales(Args _args) { // Coded by Sreenath Reddy CustInvoiceTrans custInvoiceTrans; Dialog dialog = new Dialog(“Create credit note – for sales.”); DialogField dfInv...