Monday, 20 March 2017

Security Role and privileges Label issue (Label not displayed ) AX 2012

Label text is not displayed for Security Role and privileges


In several environments I have seen some wrong security role names or other artifacts. Then instead of the role name it will display a label ID. This post will inform you about how to solve this issue in your environment if you encounter a similar issue.

Issue:

In the screenshot below, you can see the first role showing characters starting with an ape tail character ‘@’, then three capital characters and a number (e.g. @DMF501). This is a label, which should be replaced with the correct description in your language. Usually when you see this kind of label ID’s it means the label probably does not exists. In case of security artifacts it might be related to a not correctly updated role, duty or privilege name or description.
FixSecurityLabels01
The label in this example belongs to the Data Import/Export Framework and was not correctly displayed for some reason. This can also occur with other role names from e.g. an ISV, localization partner module or even your own customizations. I have not been able to reproduce it in a correct way, but I do think it might be related to a difference in system language of the source environment where a model was created and your environment of Microsoft Dynamics AX. Now we want to fix security labels in AX 2012 when you have this same issue.

Resolution:

There are some system tables in AX which do represent the roles and tasks (duties, privileges, process cycles). These tables do have the literal label ID as string instead of the language description. The name of these tables are SecurityRole and SecurityTask. These tables represent the security artifacts defined in the AOT. However they are not real tables in your Dynamics AX database. They are translated to act as tables.
Below you will find a job which can be copied into your environment. It will first do a scan which names and descriptions looks like a label ID. This works for all label files used in your environment. From the report you can decide to adjust the job to exclude some records when needed. Note that you first have to test the job in a separate environment. The coding is provided as is and you are responsible for the results in your environment. When you are not familiar in the development environment, I would suggest you ask help from a developer.
Perform the next steps to get this script in your environment.
  • Open the development workspace
  • Go to the jobs node and create a new job
  • Copy and paste the below code into the new created job.
static void MK_FixSecurityLabels(Args _args)
{
    SecurityRole    securityRole;
    SecurityTask    securityTask;
    Dialog          dialog = new Dialog(‘Fix security labels’);
    DialogField     dialogLanguage;
    DialogField     dialogCheckOnly;  
    Label           label;
 
    boolean         changed;
    boolean         checkOnly;
    int             i;

    int             j;
    LabelType       labelString;
    LanguageId      languageId;
    ;
 
    dialogLanguage  = dialog.addFieldValue(extendedTypeStr(LanguageId), SystemParameters::getSystemLanguageId());
    dialogCheckOnly = dialog.addFieldValue(extendedTypeStr(NoYesId), NoYes::Yes, ‘Check only’);
 
    if (dialog.run())
    {
        languageId  = dialogLanguage.value();
        checkOnly   = dialogCheckOnly.value();
 
        if (!languageId)
        {
            throw error(“@SYS75762”); //Language must be specified
        }
 
        label = new Label(languageId);
 
        ttsBegin;
        //Roles
        while select forUpdate securityRole
        {
            changed = false;
 
            if ((SysLabel::isLabelId(securityRole.Name) && Label.exists(securityRole.Name)))
            {
                labelString = label.extractString(securityRole.Name);
 
                if (labelString != securityRole.Name)
                {
                    info(strFmt(‘Role %1 – Name – from %2 to %3.’, securityRole.AotName, securityRole.Name, labelString));
 
                    securityRole.Name = labelString;
                    changed = true;
                    i++;
                }
            }
 
            if ((SysLabel::isLabelId(securityRole.Description) && Label.exists(securityRole.Description)))
            {
                labelString = label.extractString(securityRole.Description);
 
                if (labelString != securityRole.Description)
                {
                    info(strFmt(‘Role %1 – Description – from %2 to %3.’, securityRole.AotName, securityRole.Description, labelString));
 
                    securityRole.Description = labelString;
                    if (! changed)
                    {
                        i++;
                    }
                    changed = true;
                }
            }
 
            if (changed && !checkOnly)
            {
                securityRole.doUpdate();
            }
        }
 
        // Privileges, Duties, Process cycles
        while select forUpdate securityTask
        {
            changed = false;
 
            if ((SysLabel::isLabelId(securityTask.Name) && Label.exists(securityTask.Name)))
            {
                labelString = label.extractString(securityTask.Name);
 
                if (labelString != securityTask.Name)
                {
                    info(strFmt(‘%1 %2 – Name – from %3 to %4.’, securityTask.Type, securityTask.AotName, securityTask.Name, labelString));
 
                    securityTask.Name = labelString;
                    changed = true;
                    j++;
                }
            }
 
            if ((SysLabel::isLabelId(securityTask.Description) && Label.exists(securityTask.Description)))
            {
                labelString = label.extractString(securityTask.Description);
 
                if (labelString != securityTask.Description)
                {
                    info(strFmt(‘%1 %2 – Name – from %3 to %4.’, securityTask.Type, securityTask.AotName, securityTask.Description, labelString));
 
                    securityTask.Description = labelString;
                    if (! changed)
                    {
                        j++;
                    }
                    changed = true;
                }
            }
 
            if (changed && !checkOnly)
            {
                securityTask.doUpdate();
            }
        }
        ttsCommit;
 
        info(strFmt(‘Number of roles with wrong label: %1’, i));
        info(strFmt(‘Number of tasks with wrong label: %1’, j));
 
        if (checkOnly)
        {
            info(‘Parameter was set to check only. No updates executed.’);
        }
        else
        {
            info(‘Reported log is updated.’);
        }
    }
}
  • Save and compile the job. If there are errors in the compiler output, analyse and solve them. (Probably you missed a part during the copy process)
    Note that this job is not optimized to be free from all best practices. It contains text constants instead of labels to be able to distribute this job without having to create new labels in each environment.
  • Execute the job.
  • A dialog will appear where the Language is defaulted from your system language. The checkbox Check only will be used to first analyse which label ID’s needs to be fixed.
FixSecurityLabels02
  • Click OK. The next result will be presented. The outcome depends on the roles and tasks which are wrong in your environment.
FixSecurityLabels03
  • When there are roles, privileges, tasks or process cycles you wish to exclude, you need to adjust the select statements in the job.
  • To update the names and descriptions you need to run the job again.
  • Now disable the checkbox Check only.
FixSecurityLabels04
  • Click OK.
FixSecurityLabels05
  • Now the log will report the same, but also mentions that the reported log is updated.
  • Now check the results in the Security roles form. You will notice the labels have been fixed now.
FixSecurityLabels06
 
 

 

Import and Export file from BLOB storage Account(Azure) in D365 F&O using X++

  Import and Export file from BLOB storage Account in D365 F&O using X++ Import: /// <summary> /// MKInventQualityOrderLineService...