Create Field Security Profile Programmatically in Dataverse

Recently, my friend (Low Ming Hua) told me about an interesting scenario related to Field Security Profile. He needs to enable lots of attributes and set the Field Permission to specific teams (he also shared with me his code and I modify it!). For those who don’t know, we can enable Field-level security to control access for specific Users/Teams (to give access/forbid the access). So save this blog post in case you need it in the future!

There are multiple steps that are needed to do this operation. But the solution will not cover all of the steps needed (you need to set the Teams/Users by yourself).

The steps needed are:

Manual – Enable Column Security

You need to go to the Table that you want > go to each attribute > click Advance options > set Enable Column Security:

Enable Column Security

Manual – Create Field Security Profile

Create Security Profile

Once you already set the Fields that you want to set. You can go to your solution > click New > Security > Column security profile > you can fill in the Name and Description > click Save > go to Field Permissions section > select all the attributes that you want > click Edit and set the access level that you want:

Edit Field Security

This is the tricky part if there are lots of attributes that you want to set!

Show me the code!

This is the code I’m using for the demonstration (remember that you can give access/forbid access to specific Users/Teams. So you can change the code accordingly based on your requirement):

using Microsoft.Extensions.Configuration;
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;

var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var settings = config.GetRequiredSection("Settings").Get<AppSetting>();

var solutionUniqueName = "blog";

var entity = "contact";
var fieldLevelSecurityAttributes = new[] { 
    "address1_addresstypecode", "address1_city", "address1_composite",
    "address1_country", "address1_county", "address1_fax", "address1_freighttermscode",
    "address1_latitude","address1_line1","address1_line2","address1_line3","address1_longitude",
    "address1_name","address1_postalcode","address1_postofficebox","address1_primarycontactname",
    "address1_shippingmethodcode","address1_stateorprovince","address1_telephone1",
    "address1_telephone2","address1_telephone3","address1_upszone"
};

var client = new ServiceClient(settings.DataverseConnectionString);

var attributesMetadata = GetAttributesMetadata(client, entity, fieldLevelSecurityAttributes);
// Enable column security
foreach (var attribute in attributesMetadata)
{
    attribute.IsSecured = true;
    client.Execute(new UpdateAttributeRequest
    {
        EntityName = entity,
        Attribute = attribute
    });

    Console.WriteLine($"Updated IsSecured for {entity}.{attribute.LogicalName}'..");
}

// Create FieldSecurityProfile and put it in the solution
var fieldSecurity = (CreateResponse)client.Execute(
        CreateRequestAndAddToSolution(
            new Entity("fieldsecurityprofile")
            {
                ["name"] = "Temmy-Security-Profile",
                ["description"] = "Temmy Wahyu Raharjo Blog"
            }, solutionUniqueName));

Console.WriteLine($"FieldSecurityProfile created with id '{fieldSecurity.id}'..");

// Renew the data after the last operation
attributesMetadata = GetAttributesMetadata(client, entity, fieldLevelSecurityAttributes);

// Create FieldPermission and add it to solution
foreach (var attribute in attributesMetadata)
{
    var permission = new Entity("fieldpermission")
    {
        ["fieldsecurityprofileid"] = new EntityReference("fieldsecurityprofile", fieldSecurity.id),
        ["entityname"] = entity,
        ["attributelogicalname"] = attribute.LogicalName,
        ["cancreate"] = attribute.CanBeSecuredForCreate.GetValueOrDefault() ?
            FieldPermissionType.Allowed : FieldPermissionType.NotAllowed,
        ["canread"] = attribute.CanBeSecuredForRead.GetValueOrDefault() ?
            FieldPermissionType.Allowed : FieldPermissionType.NotAllowed,
        ["canupdate"] = attribute.CanBeSecuredForUpdate.GetValueOrDefault() ?
            FieldPermissionType.Allowed : FieldPermissionType.NotAllowed
    };
    var fieldPermission = (CreateResponse)client.Execute(
        CreateRequestAndAddToSolution(permission, solutionUniqueName));

    Console.WriteLine($"Field Permission created for '{entity}.{attribute.LogicalName}' with id '{fieldPermission.id}'..");
}

static AttributeMetadata[] GetAttributesMetadata(IOrganizationServiceAsync service, 
    string entityName, string[] filterAttributes)
{
    var attributes = (RetrieveEntityResponse)service.Execute(new RetrieveEntityRequest
    {
        EntityFilters = Microsoft.Xrm.Sdk.Metadata.EntityFilters.Attributes,
        LogicalName = entityName
    });

    return attributes.EntityMetadata.Attributes
            .Where(e => filterAttributes.Contains(e.LogicalName)).ToArray();
}

static CreateRequest CreateRequestAndAddToSolution(Entity target, string solutionUniqueName)
{
    return new CreateRequest { Target = target, ["SolutionUniqueName"] = solutionUniqueName };
}

Console.ReadKey();

To associate the record to the solution, we can use the “SolutionUniqueName” parameter in CreateRequest that you can find in this documentation. This will help us to create the record and automatically add to the solution that we targeted in order for us to do export-import to another environment!

And hey, I changed my code to use the newest DataverseServiceClient after their GA.

😎

This is the result:

The Result!

And for the last part, don’t forget to go to the Members (Teams/Users) and set them manually!

Add the members manually (Teams/Users)

Happy CRM-ing!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.