{"id":41762,"date":"2025-07-14T14:24:55","date_gmt":"2025-07-14T08:54:55","guid":{"rendered":"https:\/\/www.inogic.com\/blog\/?p=41762"},"modified":"2025-07-14T14:24:55","modified_gmt":"2025-07-14T08:54:55","slug":"simplify-dynamics-365-privileges-with-retrieveusersetofprivilegesbyidsrequest","status":"publish","type":"post","link":"https:\/\/www.inogic.com\/blog\/2025\/07\/simplify-dynamics-365-privileges-with-retrieveusersetofprivilegesbyidsrequest\/","title":{"rendered":"Simplify Dynamics 365 Privileges with RetrieveUserSetOfPrivilegesByIdsRequest"},"content":{"rendered":"<p><img decoding=\"async\" class=\"alignnone size-full wp-image-41767\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/Proactive-License-Validation-in-Dynamics-365_-Streamlining-with-RetrieveUserLicenseInfoRequest.png\" alt=\"Dynamics 365 Privileges \" width=\"1400\" height=\"800\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/Proactive-License-Validation-in-Dynamics-365_-Streamlining-with-RetrieveUserLicenseInfoRequest.png 1400w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/Proactive-License-Validation-in-Dynamics-365_-Streamlining-with-RetrieveUserLicenseInfoRequest-300x171.png 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/Proactive-License-Validation-in-Dynamics-365_-Streamlining-with-RetrieveUserLicenseInfoRequest-1024x585.png 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/Proactive-License-Validation-in-Dynamics-365_-Streamlining-with-RetrieveUserLicenseInfoRequest-768x439.png 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/Proactive-License-Validation-in-Dynamics-365_-Streamlining-with-RetrieveUserLicenseInfoRequest-660x377.png 660w\" sizes=\"(max-width: 1400px) 100vw, 1400px\" \/><\/p>\n<p>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:<\/p>\n<ul>\n<li>The FetchXML was large, hard to maintain, and error-prone due to its multiple joins and filters.<\/li>\n<li>It performed poorly on large datasets, especially in our organization with thousands of users and complex security roles.<\/li>\n<li>Updating the query to include new privileges was time-consuming and required frequent maintenance.<\/li>\n<\/ul>\n<p>While exploring alternatives for this, the <strong>RetrieveUserSetOfPrivilegesByIdsRequest <\/strong>class in <em>Microsoft.Crm.Sdk.Messages <\/em>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.<\/p>\n<p>In this blog, you\u2019ll learn how you can use this request to streamline your workflow, understand its key components (<em>UserId<\/em>, <em>PrivilegeIds<\/em>, and <em>RolePrivileges<\/em>), see the code used to replace the FetchXML, and discover the benefits you can gain.<\/p>\n<p><strong>Approach: Replacing FetchXML with RetrieveUserSetOfPrivilegesByIdsRequest<\/strong><\/p>\n<p>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\u2019ll find a simplified example of a similar FetchXML query, highlighting the challenges encountered:<\/p>\n<pre class=\"lang:css gutter:true start:1\">fetch mapping=\"logical\" no-lock=\"true\"&gt;\r\n\r\n&lt;entity name=\"systemuser\"&gt;\r\n\r\n&lt;attribute name=\"systemuserid\"\/&gt;\r\n\r\n&lt;attribute name=\"fullname\"\/&gt;\r\n\r\n&lt;filter type=\"and\"&gt;\r\n\r\n&lt;condition attribute=\"isdisabled\" operator=\"eq\" value=\"0\"\/&gt;\r\n\r\n&lt;\/filter&gt;\r\n\r\n&lt;link-entity name=\"systemuserroles\" from=\"systemuserid\" to=\"systemuserid\" alias=\"sur\"&gt;\r\n\r\n&lt;link-entity name=\"role\" from=\"roleid\" to=\"roleid\" alias=\"r\"&gt;\r\n\r\n&lt;link-entity name=\"roleprivileges\" from=\"roleid\" to=\"roleid\" alias=\"rp\"&gt;\r\n\r\n&lt;attribute name=\"privilegeid\"\/&gt;\r\n\r\n&lt;attribute name=\"privilegedepthmask\"\/&gt;\r\n\r\n&lt;filter type=\"and\"&gt;\r\n\r\n&lt;condition attribute=\"privilegeid\" operator=\"in\"&gt;\r\n\r\n&lt;value&gt;886b280c-6396-4d56-a0a3-2c1b0a50ceb0&lt;\/value&gt; &lt;!-- prvReadQuote--&gt;\r\n\r\n&lt;\/condition&gt;\r\n\r\n&lt;\/filter&gt;\r\n\r\n&lt;\/link-entity&gt;\r\n\r\n&lt;\/link-entity&gt;\r\n\r\n&lt;\/link-entity&gt;\r\n\r\n&lt;\/entity&gt;\r\n\r\n&lt;\/fetch&gt;<\/pre>\n<p>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.<\/p>\n<p>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.<\/p>\n<p>To address this, you can replace your FetchXML logic with the <strong>RetrieveUserSetOfPrivilegesByIdsRequest <\/strong>to directly retrieve privilege information for specified users and privilege IDs. Below is the code snippet that replaced the FetchXML logic:<\/p>\n<h3><strong>Step 1: Define the User ID<\/strong><\/h3>\n<p>You can start by specifying the user ID for the user whose privileges you want to check. This ensures you\u2019re targeting the right user for compliance verification.<\/p>\n<p>Guid userId = new Guid(&#8220;fb973ba0-1323-f011-8c4d-6045bdceacc4&#8221;);<\/p>\n<p><strong>Step 2: Define the Privilege IDs<\/strong><\/p>\n<p>Specify the privilege IDs you want to check. For example, if you\u2019re focused on prvReadQuote, you can define it like this:<\/p>\n<pre class=\"lang:css gutter:true start:1\">\/\/ Define the privilege IDs to check (<em>prvReadQuote<\/em>)\r\nGuid[] privilegeIds = new Guid[]\r\n{\r\nnew Guid(\"00a8d04e-ede7-4884-ae18-09c6e55344ca\")\r\n};<\/pre>\n<p><strong>Step 3: Execute the Request and Process the Response<\/strong><\/p>\n<p>Create and execute the <strong>RetrieveUserSetOfPrivilegesByIdsRequest<\/strong>, process the response to check for privileges, and exit the loop after finding <em>prvReadQuote <\/em>to optimize processing.<\/p>\n<pre class=\"lang:css gutter:true start:1\">\/\/ Create and execute RetrieveUserSetOfPrivilegesByIdsRequest\r\nvar request = new RetrieveUserSetOfPrivilegesByIdsRequest\r\n{\r\nUserId = userId,\r\nPrivilegeIds = privilegeIds\r\n};\r\nvar response = (RetrieveUserSetOfPrivilegesByIdsResponse)service.Execute(request);\r\n\r\nif (response.RolePrivileges.Length == 0)\r\n{\r\nConsole.WriteLine(\"No privileges found for the user.\");\r\n}\r\n\r\n\/\/ Process the response for privilege retrieval\r\nforeach (var privilege in response.RolePrivileges)\r\n{\r\nif (privilege.PrivilegeName == \"prvReadQuote\")\r\n{\r\nConsole.WriteLine($\"Privilege Name : {privilege.PrivilegeName}\");\r\nConsole.WriteLine($\"Privilege ID: {privilege.PrivilegeId}\");\r\nConsole.WriteLine($\"Business Unit ID: {privilege.BusinessUnitId}\");\r\nConsole.WriteLine($\"Depth: {privilege.Depth}\");\r\nBreak;\r\n}\r\n}<\/pre>\n<p><strong>Key Components:<\/strong><\/p>\n<p><strong>RetrieveUserSetOfPrivilegesByIdsRequest Properties<\/strong>:<\/p>\n<ol>\n<li><em>UserId<\/em>: The Guid value of the user whose privileges are being retrieved.<\/li>\n<li><em>PrivilegeIds<\/em>: An array of Guid values specifying the privilege IDs to check<\/li>\n<\/ol>\n<p><strong>RetrieveUserSetOfPrivilegesByIdsResponse Property<\/strong>:<\/p>\n<ol>\n<li><em>RolePrivileges<\/em>: The response, <strong>RetrieveUserSetOfPrivilegesByIdsResponse<\/strong>, gets an array of privileges that the user holds.<\/li>\n<\/ol>\n<p><strong>Output:<br \/>\n<\/strong><strong><br \/>\n<\/strong>You can refer to the screenshot below for the detailed information on the retrieved privileges.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-41763\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/1Dynamics-365-Privileges.png\" alt=\"Dynamics 365 Privileges\" width=\"1920\" height=\"1041\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/1Dynamics-365-Privileges.png 1920w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/1Dynamics-365-Privileges-300x163.png 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/1Dynamics-365-Privileges-1024x555.png 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/1Dynamics-365-Privileges-768x416.png 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/1Dynamics-365-Privileges-1536x833.png 1536w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2025\/07\/1Dynamics-365-Privileges-660x358.png 660w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/p>\n<p>This output provides a clear and concise view of the retrieved privilege information held by the user, specifically highlighting the <em>prvReadQuote <\/em>privilege with its PrivilegeId, BusinessUnitId, and Depth when found, fulfilling our task of retrieving privilege information for compliance purposes.<\/p>\n<h2><strong>Conclusion: Real Efficiency Gains<\/strong><\/h2>\n<p>By replacing the complex FetchXML query with the <strong>RetrieveUserSetOfPrivilegesByIdsRequest<\/strong>, one can significantly simplify the task of retrieving user privileges in Dynamics 365.<\/p>\n<p>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.<\/p>\n<p>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&#8217;s highest effective depth for each privilege.<\/p>\n<p>If you&#8217;re looking to streamline privilege management in your environment, this request is worth considering.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.inogic.com\/blog\/2025\/07\/simplify-dynamics-365-privileges-with-retrieveusersetofprivilegesbyidsrequest\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[16,2361],"tags":[3182,3183],"class_list":["post-41762","post","type-post","status-publish","format-standard","hentry","category-dynamics-365","category-technical","tag-dynamics-365-privileges","tag-retrieveusersetofprivilegesbyidsrequest"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/41762","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/comments?post=41762"}],"version-history":[{"count":0,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/41762\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media?parent=41762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/categories?post=41762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/tags?post=41762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}