Simplify Dynamics 365 Privileges with RetrieveUserSetOfPrivilegesByIdsRequest

By | July 14, 2025

Dynamics 365 Privileges

Verifying user privileges in Dynamics 365, such as access to prvReadQuote for compliance or operational purposes, often involves identifying which users hold specific privileges. Initially, a complex FetchXML query was used to retrieve this data, but it posed significant challenges:

  • The FetchXML was large, hard to maintain, and error-prone due to its multiple joins and filters.
  • It performed poorly on large datasets, especially in our organization with thousands of users and complex security roles.
  • Updating the query to include new privileges was time-consuming and required frequent maintenance.

While exploring alternatives for this, the RetrieveUserSetOfPrivilegesByIdsRequest class in Microsoft.Crm.Sdk.Messages was discovered. This request lets you retrieve privilege data directly by UserId and PrivilegeIds, making the process faster and far easier to maintain, eliminating the need for FetchXML.

In this blog, you’ll learn how you can use this request to streamline your workflow, understand its key components (UserId, PrivilegeIds, and RolePrivileges), see the code used to replace the FetchXML, and discover the benefits you can gain.

Approach: Replacing FetchXML with RetrieveUserSetOfPrivilegesByIdsRequest

Initially, a FetchXML query was used to retrieve user privilege information, such as prvReadQuote, by joining multiple entities. This approach was complex and cumbersome. Below, you’ll find a simplified example of a similar FetchXML query, highlighting the challenges encountered:

fetch mapping="logical" no-lock="true">

<entity name="systemuser">

<attribute name="systemuserid"/>

<attribute name="fullname"/>

<filter type="and">

<condition attribute="isdisabled" operator="eq" value="0"/>

</filter>

<link-entity name="systemuserroles" from="systemuserid" to="systemuserid" alias="sur">

<link-entity name="role" from="roleid" to="roleid" alias="r">

<link-entity name="roleprivileges" from="roleid" to="roleid" alias="rp">

<attribute name="privilegeid"/>

<attribute name="privilegedepthmask"/>

<filter type="and">

<condition attribute="privilegeid" operator="in">

<value>886b280c-6396-4d56-a0a3-2c1b0a50ceb0</value> <!-- prvReadQuote-->

</condition>

</filter>

</link-entity>

</link-entity>

</link-entity>

</entity>

</fetch>

The above FetchXML proved to be inefficient because it involved multiple chained queries across related entities. For each user, it first retrieved the security role associations from the systemuserroles entity, then fetched role metadata from the role entity, and finally gathered privilege information from the roleprivileges entity.

This multi-level traversal resulted in slow performance, particularly in environments with a large number of users and complex role hierarchies. It also made the query harder to maintain, particularly when new privileges had to be checked or logic needed to be updated.

To address this, you can replace your FetchXML logic with the RetrieveUserSetOfPrivilegesByIdsRequest to directly retrieve privilege information for specified users and privilege IDs. Below is the code snippet that replaced the FetchXML logic:

Step 1: Define the User ID

You can start by specifying the user ID for the user whose privileges you want to check. This ensures you’re targeting the right user for compliance verification.

Guid userId = new Guid(“fb973ba0-1323-f011-8c4d-6045bdceacc4”);

Step 2: Define the Privilege IDs

Specify the privilege IDs you want to check. For example, if you’re focused on prvReadQuote, you can define it like this:

// Define the privilege IDs to check (prvReadQuote)
Guid[] privilegeIds = new Guid[]
{
new Guid("00a8d04e-ede7-4884-ae18-09c6e55344ca")
};

Step 3: Execute the Request and Process the Response

Create and execute the RetrieveUserSetOfPrivilegesByIdsRequest, process the response to check for privileges, and exit the loop after finding prvReadQuote to optimize processing.

// Create and execute RetrieveUserSetOfPrivilegesByIdsRequest
var request = new RetrieveUserSetOfPrivilegesByIdsRequest
{
UserId = userId,
PrivilegeIds = privilegeIds
};
var response = (RetrieveUserSetOfPrivilegesByIdsResponse)service.Execute(request);

if (response.RolePrivileges.Length == 0)
{
Console.WriteLine("No privileges found for the user.");
}

// Process the response for privilege retrieval
foreach (var privilege in response.RolePrivileges)
{
if (privilege.PrivilegeName == "prvReadQuote")
{
Console.WriteLine($"Privilege Name : {privilege.PrivilegeName}");
Console.WriteLine($"Privilege ID: {privilege.PrivilegeId}");
Console.WriteLine($"Business Unit ID: {privilege.BusinessUnitId}");
Console.WriteLine($"Depth: {privilege.Depth}");
Break;
}
}

Key Components:

RetrieveUserSetOfPrivilegesByIdsRequest Properties:

  1. UserId: The Guid value of the user whose privileges are being retrieved.
  2. PrivilegeIds: An array of Guid values specifying the privilege IDs to check

RetrieveUserSetOfPrivilegesByIdsResponse Property:

  1. RolePrivileges: The response, RetrieveUserSetOfPrivilegesByIdsResponse, gets an array of privileges that the user holds.

Output:

You can refer to the screenshot below for the detailed information on the retrieved privileges.

Dynamics 365 Privileges

This output provides a clear and concise view of the retrieved privilege information held by the user, specifically highlighting the prvReadQuote privilege with its PrivilegeId, BusinessUnitId, and Depth when found, fulfilling our task of retrieving privilege information for compliance purposes.

Conclusion: Real Efficiency Gains

By replacing the complex FetchXML query with the RetrieveUserSetOfPrivilegesByIdsRequest, one can significantly simplify the task of retrieving user privileges in Dynamics 365.

This approach reduces development complexity, improves performance across large datasets, and offers a scalable way to validate user access through a well-structured response model.

Additionally, unlike FetchXML, which retrieves all privilege entries for the security roles and requires additional LINQ queries or logic to determine the maximum depth, this request automatically returns the user’s highest effective depth for each privilege.

If you’re looking to streamline privilege management in your environment, this request is worth considering.

Category: Dynamics 365 Technical Tags: ,

About Sam Kumar

Sam Kumar is the Vice President of Marketing at Inogic, a Microsoft Gold ISV Partner renowned for its innovative apps for Dynamics 365 CRM and Power Apps. With a rich history in Dynamics 365 and Power Platform development, Sam leads a team of certified CRM developers dedicated to pioneering cutting-edge technologies with Copilot and Azure AI the latest additions. Passionate about transforming the CRM industry, Sam’s insights and leadership drive Inogic’s mission to change the “Dynamics” of CRM.