Consider the situation where a field on a Dynamics 365 form needs to be either shown or hidden based on whether the logged in user has a particular security role. This is usually achieved by calling the following client API.
let userSettings = Xrm.Utility.getGlobalContext().userSettings.securityRoles
This API returns the display name of each of the security role assigned to the user (user roles) and any security roles assigned to the team (team roles) that the user is associated with. For example,
- name = ‘Record Officer’
- id = 21ad683f-1b06-4a05-b8f3-9c00da-7bc91b
So, if the requirement was to hide a certain field on a form for a ‘Record Officer’, the logic would iterate thru the logged in user’s retrieved security roles. If one of those roles had the id = 21ad683f-1b06-4a05-b8f3-9c00da-7bc91b, it would then hide that particular field on the form
This approach works fine in most circumstances, however…
An issue with this approach

Consider the situation where a TypeScript developer is writing code for the case where the logged in user is residing in the ‘Services’ child business unit (Figure 1). When the developer is working in their Dev 1 environment (Figure 2), they would hardcode the ‘Record Officer’ role to an id of 21ad683f-1b06-4a05-b8f3-9c00da-7bc91b. However, when the code is moved to Sit 1 (Figure 3), the id is different and thus the TypeScript code would stop working


Solution
Referring to Figures 2 & 3, when moving between environments, the parent business unit role id doesn’t change. Thus, this is the id that needs to be referenced in the typescript code. This code (shown below) would be used in place of Xrm.Utility.getGlobalContext().userSettings.securityRoles
private async isCurrentUserAssignedSecurityRole(securityRole: string): Promise<boolean> {
try {
const userId = Xrm.Utility.getGlobalContext().userSettings.userId;
const user = userId.slice(1, -1);
let resultTeamRoles, resultSystemUserRoles;
//retrieve team roles
let teamRolesFetchXml = `<fetch>
<entity name = "systemuser" >
<attribute name="systemuserid" />
<filter>
<condition attribute="systemuserid" operator="eq" value="${user}" />
</filter>
<link-entity name="teammembership" intersect="true" visible="false" to="systemuserid" from="systemuserid" >
<link-entity name="team" to="teamid" from="teamid" alias="team" />
<link-entity name="teamroles" to="teamid" from="teamid" intersect="true" visible="false" >
<link-entity name="role" alias="role" to="roleid" from="roleid" >
<filter>
<condition attribute="parentrootroleid" operator = "eq" value = "${securityRole}" />
</filter>
</link-entity>
</link-entity>
</link-entity>
</entity>
</fetch>`;
let teamRolesFetchXmlQuery = '?fetchXml=' + encodeURIComponent(teamRolesFetchXml);
resultTeamRoles = await Xrm.WebApi.retrieveMultipleRecords('systemuser', teamRolesFetchXmlQuery);
if (resultTeamRoles.entities.length > 0) {
return true;
}
//retrieve user roles
let userRolesFetchXml = `<fetch>
<entity name="systemuser">
<attribute name="systemuserid" />
<filter>
<condition attribute="systemuserid" operator="eq" value="${user}" />
</filter>
<link-entity name="systemuserroles" from="systemuserid" to="systemuserid">
<link-entity name="role" from="roleid" to="roleid">
<filter>
<condition attribute="parentrootroleid" operator="eq" value="${securityRole}" />
</filter>
</link-entity>
</link-entity>
</entity>
</fetch>`;
let userRolesFetchXmlQuery = '?fetchXml=' + encodeURIComponent(userRolesFetchXml);
resultSystemUserRoles = await Xrm.WebApi.retrieveMultipleRecords('systemuser', userRolesFetchXmlQuery);
return (resultSystemUserRoles.entities.length > 0) ? true : false;
} catch (e: any) {
console.error('The following error occured in isCurrentUserAssignedSecurityRole = ' + e);
throw e;
}
}
An example of calling this function is as follows
const RecordOfficerRoleID = '9d40a5db-367b-ed11-81ad-000d3a6ad3e8';
const isUserRecordOfficer = await this.isCurrentUserAssignedSecurityRole(RecordOfficerRoleID);
Further reading
Maintain the same GUIDs in dynamics 365 environments
References
https://community.dynamics.com/blogs/post/?postid=fdd9d3bc-9f66-41c6-be40-4a1258724ef4