Enable Modified by and Created by on ALL Parameters tables

Handy Code to have , Can be use to change any of the property of a table also just with the slightest change.


static void Waj_EnableProperties(Args _args)


SysDictTable dictTable,sysDictTable;
TreeNode node;
#AOT Name name;
TreeNode treeNode;
str indexName;

treeNode = TreeNode::findNode(#TablesPath);
treeNode = treeNode.AOTfirstChild();

while (treeNode)

name = treeNode.AOTname();
sysDictTable = SysDictTable::newTableId(treeNode.applObjectId());

if ((sysDictTable.tableGroup() == tableGroup::Parameter ||
sysDictTable.tableGroup() == tableGroup::Group) &&
!sysDictTable.isMap() &&
!sysDictTable.isTmp() &&
!sysDictTable.isView() &&

node = SysDictTable.treeNode();
node.AOTsetProperty(#PropertyCreatedBy, #PropertyValueYes);

node.AOTsetProperty(#PropertyCreatedDateTime, #PropertyValueYes);
node.AOTsetProperty(#PropertyModifiedBy, #PropertyValueYes);
node.AOTsetProperty(#PropertyModifiedDateTime, #PropertyValueYes);


node = null;




Create Default dimension using x++

The following job will get a DimensionAttributeValueSet record ID base on the a set of dimension values.


static void CreateDefaultDimensions(Args _args)
PurchTable purchTable;
DimensionAttributeValueSetStorage valueSetStorage = new DimensionAttributeValueSetStorage();
DimensionDefault result;

int i;
DimensionAttribute dimensionAttribute;
DimensionAttributeValue dimensionAttributeValue;

// Note that “Item” is not one of the default dimension,
// but DimensionAttributeValueSetStorage will handle it gracefully
container conAttr = [“Project”, “Vendor”]; // Dimensions
container conValue = [“1001”, “Ven-0046”]; //  respective Values
str dimValue;

purchTable = purchTable::find(‘000471’);

for (i = 1; i <= conLen(conAttr); i++)
dimensionAttribute = dimensionAttribute::findByName(conPeek(conAttr,i));

if (dimensionAttribute.RecId == 0)

dimValue = conPeek(conValue,i);

if (dimValue != “”)
// The last parameter is “true”. A dimensionAttributeValue record will be created if not found.
dimensionAttributeValue =

// Add the dimensionAttibuteValue to the default dimension

result = valueSetStorage.save();
purchTable.DefaultDimension = result;

Process Industries Add-On for Microsoft Dynamics AX 2009

Recently  I got a requirement to install PI 2009 on one of my client. What I figured is the sequence of installation is very important

Here are the steps to follow:

1. Install AX2009 RTM (SYS layer)
2. Install SP1 (SYP layer)
3. Install GLS layer if needed
4. Install Process Industries (BUS layer (compatible with existing GLS))
5. Install RU7 (SYP (+ GLP layer))
6. Install PI BUP layer (specific to localization)
7. Open AX client and run Installation Checklist


BUP layers Installation file Download link is here


Hope this will save Some on time 🙂


Send email from AX using exchange servers

There are number of posts to sent emails from AX using Hotmail(Live) or gmail exchange server. This is really helpful when we don’t have exchange is in place due to high cost or you just want to send emails for testing or demo purpose, so in this case we can use this method .

To achieve this requirement go to System Administration | Setup | System | E-mail parameters

P.S. I am using a dedicated email account at outlook (Hotmail) domain for this example.

Email parameters


Here is the job I wrote to send email for selected user. I name it SendTextMail as in my following post I will be writing to send invitation from AX using Hotmail or Gmail exchange server.


staticvoid SendTextMail(Args _args)


System.Net.Mail.MailMessage             mailMessage;

System.Net.Mail.SmtpClient              myMail;

System.Net.Mail.MailAddressCollection   mailcoll;

System.Net.Mail.MailAddress             mailFrom;

System.Net.Mail.MailAddress             mailTo;

System.Net.Mail.MailAddress             mailCC;

str                                     receiverMailAddress;

str                                     mailBody;

str                                     smtpServer;

str                                     mailSubject;

str                                     CcMailAddress;

int                                     SMTPPort;


str                                     mail;

str                                     pwd;

Dialog dialog = new Dialog(‘Email’);

Dialogfield     person, emailSubject, emailBody;

HcmWorker       hcmWorker;

UserInfo        userInfo;

DirPersonUser   dirPersonUser;

SysUserInfo     sysUserInfo;

SysEmailParameters parameters;

// dialog field to select user to whom email will be send

person          = dialog.addField(extendedTypeStr(HcmWorkerRecId ), ‘Person :’ );

emailSubject    = dialog.addField(extendedTypeStr(Description), ‘Subject :’ );      // Email Subject

emailBody       = dialog.addField(extendedTypeStr(Notes), ‘Body :’ );               // Email Body



parameters = SysEmailParameters::find();   // Find values from Email Parameters

new InteropPermission(InteropKind::ClrInterop).assert();

        // gets HcmWorker record based on person selected from user dialog

hcmWorker = hcmWorker::find(person.value());

if(!hcmWorker.RecId)   // Verify either user exist or not


throw error(‘User not found’);


selectfirstOnly dirPersonUser

join userInfo

where dirPersonUser.PersonParty == DirPartyTable::findByName(hcmWorker.name()).RecId &&

userInfo.id == dirPersonUser.User;

selectfirstOnly sysUserInfo

where sysUserInfo.Id == userInfo.id;      // Retrieve user info record for selected user

mailSubject         = emailSubject.value();

mailFrom            = new  System.Net.Mail.MailAddress(parameters.SMTPUserName ,”Name”);

mailTo              = new  System.Net.Mail.MailAddress(sysUserInfo.Email);

//mailTo            = new  System.Net.Mail.MailAddress(“test1@gmail.com”);

//mailCC            = new  System.Net.Mail.MailAddress(“test2@gmail.com”;

mailcoll            = new  System.Net.Mail.MailAddressCollection();

mailBody            = emailBody.value();



            // using the SMTP server ip //setup in email Parameters

smtpServer          = SysEmaiLParameters::find(false).SMTPRelayServerName;

mailMessage         = new System.Net.Mail.MailMessage(mailFrom,mailTo);



SMTPPort            = SysEmaiLParameters::find(false).SMTPPortNumber;

myMail              = new System.Net.Mail.SmtpClient(smtpServer, SMTPPort);

           // For SSL enabled mail servers. Ex: gmail, smtp.gmail.com, port 465 or 587


pwd = SysEmaiLParameters::password();

mymail.set_Credentials(New System.Net.NetworkCredential(parameters.SMTPUserName, pwd));





throw Exception::CLRError;






After running this job You will get this UI from where you will select person , Subject of email . and Body of email to sent click OK.



How to avoid Startup “The model store has been modified” ?

Recently on some clients they got the checklist popup on start of ax .CheckList



In my case the field MinorUpgrade in table ReleaseUpdateConfiguration was set to 1, so the checklist always opened.

I fixed this using a job having this code:


Hint: AX usesInfo class on start of ax to load and check necessory things and info.startup() to check, if checklist must be opened