When approaching what I consider to be a pretty straightforward problem, I always think to myself, “I can’t be the first one to have had this issue.” Not only that, on the day of AI, when I think a task should take minutes, I actually spend hours trying to figure it out.
Case in point, the other day, I wanted to get a one-page view of which forms in PowerApps had specific security roles assigned to them.
I thought this would be a pretty straightforward problem set, after all, who would want to go through over 300 tables to figure this out?
- XRM toolbox – had nothing that didn’t force me to do extra work on my own.
- AI – Despite my attempts, they couldn’t find the secret sauce.
At one point, I was ready to give up, but I knew that the link between Forms and Security Roles existed, so I popped open FormXml Manager to inspect the form structure in PowerApps.
Sure enough, at the bottom of the form, XML was the information I was looking for – DisplayConditions.
If your form has no DisplayConditions associated with it, by default it will show <Everyone>.

However, if your form has security roles tied to it, then you will see something like this.

Now, alone that doesn’t do much for me, because I still did not want to go through each form, opening, searching and closing it.
The Code
The solution was to write some code that would get all the forms and their DisplayConditions, and then get their associated security role(s) for each form. In the first query listed below, the commented out filter “objecttypecode” relates specifically to the Contact entity; however, as I said, I wanted everything.
QueryExpression securityQuery = new QueryExpression(“systemform”);
securityQuery.ColumnSet = new ColumnSet(“name”, “type”, “objecttypecode”, “formid”);
//query.Criteria.AddCondition(new ConditionExpression(“objecttypecode”, ConditionOperator.Equal,2));
var results = _connection.Organization.RetrieveMultiple(securityQuery);
foreach (var entity in results.Entities)
{
var form = _connection.Organization.Retrieve(“systemform”, entity.Id, new ColumnSet(“name”, “formxml”));
var formXml = form.GetAttributeValue<string>("formxml");
var doc = new XmlDocument();
doc.LoadXml(formXml);
var roleNodes = doc.SelectNodes("//form/DisplayConditions/Role");
if (roleNodes.Count > 0)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Form '{form.GetAttributeValue<string>("name")}' is restricted to roles:");
Console.ResetColor();
foreach (XmlNode roleNode in roleNodes)
{
Guid roleId = new System.Guid(roleNode.Attributes["Id"]?.Value.ToString());
try
{
var securityRole = _connection.Organization.Retrieve("role", roleId, new ColumnSet("name"));
Console.WriteLine($"Role ID: {roleId}, Name: {securityRole.GetAttributeValue<string>("name")}");
}
catch (Exception ex) {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Role ID: {roleId} not found, Exception: {ex}");
Console.ResetColor();
}
}
}
}
Once executed, you will receive a list of all the forms in use in your system that have custom security roles attached to them.
Problem solved.