> For the complete documentation index, see [llms.txt](https://documentation.grax.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.grax.com/other/permissions-and-access/integration-user/scripts.md).

# Scripts

These scripts are intended for use only when `Auto Config` does not work in your Salesforce org. They are not required for most customers.

## Creating the GRAX\_Integration\_User Permission Set manually

1. Open the [Salesforce Developer Console](https://help.salesforce.com/s/articleView?id=sf.code_dev_console_opening.htm\&type=5)
2. Open the `Debug` menu
3. Select `Open Execute Anonymous Window` (or press `CTRL + E`)
4. Copy the script below into the `Enter Apex Code` dialog
5. Select the `Open Log` checkbox
6. Click `Execute`
7. Assign the new '*GRAX\_Integration\_User*' permission set to the GRAX Integration User.

```apex
PermissionSet piu = new PermissionSet(
    Name = 'GRAX_Integration_User',
    Label = 'GRAX Integration User Permission',
    Description='Grants users permission to read and update records, fields and files for GRAX backup, archive and restore',
    PermissionsApiEnabled=true,
    PermissionsViewAllData=true,
    PermissionsModifyAllData=true,
    PermissionsQueryAllFiles=true
);

DescribeSobjectResult permissionSetDescribe = Schema.PermissionSet.SObjectType.getDescribe();
Map<String, SObjectField> fieldMap = permissionSetDescribe.fields.getMap();
List<String> availablePermissions = new List<String>();

for (String fieldName : fieldMap.keySet()) {
    if (!fieldName.startsWithIgnoreCase('Permissions')) {
        continue;
    }
    if (fieldName == 'PermissionsCreateAuditFields') {
        System.debug('Setting PermissionsCreateAuditFields=true');
        piu.put(fieldName, true);
    }
    if (fieldName == 'PermissionsViewAllData' ||
            fieldName == 'PermissionsModifyAllData' ||
            fieldName == 'PermissionsQueryAllFiles') {
                continue;
    }
    DescribeFieldResult fd = fieldMap.get(fieldName).getDescribe();
    if (fd.isCreateable() && fd.isUpdateable()) {
        availablePermissions.add(fieldName);
    }
}
Integer count = 1;

while (count < 11) {
    try {
        insert piu;
        count = 100;
    } catch(DmlException e) {
        count++;
        List<String> splitError = e.getMessage().split(' ');

        for (String str : splitError){
            string check = str.removeEnd(',');
            check = check.removeEnd(':');
            for (String fieldName : availablePermissions){
                if (fieldName == 'Permissions' + check){
                    piu.put(fieldName, true);
                }
            }
        }
    }
}
```

## Fixing Field Level Security manually

### Option 1: Apex FLS Script

The GRAX-provided Apex script below is an effective solution for updating field-level permissions on a large number of objects. However, there are a few cases in which the script may not be ideal:

1. Very large number of objects
2. Very large number of fields

The script makes a best effort to handle Apex row/batch limits. This means that you need to run the script multiple times if a large number of objects are processed. The script outputs `Apex batch limits reached. Please run again for next batch.` if another run is required.

If you encounter Apex limit errors, errors related to specific objects, or validation errors while running this script, fallback to the web-tools option below for updating the objects that remain.

**NOTE:** this section assumes you've used the script above to provision a `GRAX_Integration_User` Permission Set. If you don't have a permission set with this name in your org, the script fails.

**ALSO NOTE:** this script grants access to fields we're able to find in the Salesforce metadata. *This may not be a comprehensive list*. GRAX Admins should review the `GRAX_Integration_User` Permission Set's Field Permissions for each object to ensure access is granted to all fields.

#### **Running the FLS Script**

1. Open the [Salesforce Developer Console](https://help.salesforce.com/s/articleView?id=sf.code_dev_console_opening.htm\&type=5)
2. Open the `Debug` menu
3. Select `Open Execute Anonymous Window` (or press `CTRL + E`)
4. Copy the script below into the `Enter Apex Code` dialog
5. Select the `Open Log` checkbox
6. Click `Execute`
7. In the `Execution Log` window, select the `Debug Only` checkbox
8. If the last log entry prompts a re-run, return to the `Execute Anonymous Window` and repeat the subsequent steps until the last entry no longer prompts a re-run.

```apex
// decrease the maxBatchSize if a `System.LimitException: Too many query rows: 50001` error is returned
Integer maxBatchSize = 1000;

PermissionSet[] lpsGIU = [SELECT Id FROM PermissionSet WHERE name = 'GRAX_Integration_User'];
if (lpsGIU.isempty()) {
    System.debug('GRAX_Integration_User PermissionSet not found');
    return;
}

// Use the 25 oldest permissionSets with ViewAllData Permissions to model the fields to grant access to
PermissionSet[] lpsModel = [
    SELECT Id
    FROM PermissionSet
    WHERE PermissionsViewAllData = true
    AND id != :lpsGIU[0].Id
    ORDER BY CreatedDate
    LIMIT 25];

List<Id> modelPSIds = new List<Id>();
for (PermissionSet psID : lpsModel) {
    Id tmpID = (Id) psID.get('Id');
    modelPSIds.add(tmpID);
}

if (modelPSIds.isempty()) {
    // No viewAllData PermissionSet were found, use the 25 oldest permissionSets
    PermissionSet[] lpsProfile = [
        SELECT Id
        FROM PermissionSet
        WHERE ProfileId != ''
        AND id != :lpsGIU[0].Id
        ORDER BY CreatedDate
        LIMIT 25];
    for (PermissionSet psID : lpsProfile) {
        Id tmpID = (Id) psID.get('Id');
        modelPSIds.add(tmpID);
    }
}

if (modelPSIds.isempty()) {
    System.debug('no PermissionSets to model');
    return;
}

system.debug(modelPSIds);

List<AggregateResult> aggHas = new List<AggregateResult>([
    SELECT SObjectType
    FROM FieldPermissions
    WHERE ParentID = :lpsGIU[0].Id
    GROUP BY SObjectType]);

Set<String> hasObj = new Set<String>();
for (AggregateResult obj : aggHas) {
    String tmpObj = (String) obj.get('SobjectType');
    hasObj.add(tmpObj);
}

List<AggregateResult> aggAll = new List<AggregateResult>([
    SELECT SObjectType
    FROM ObjectPermissions
    GROUP BY SObjectType
    ORDER BY SObjectType
]);

String [] objectsToFix = new List<String>();

for (AggregateResult obj : aggAll) {
    String tmpObj = (String) obj.get('SobjectType');
    if (!hasObj.contains(tmpObj)){
        objectsToFix.add(tmpObj);
    }
    if (objectsToFix.size() >= maxBatchSize) {
        System.debug('Max batch size reached. Please run again for next batch.');
        break;
    }
}

List<AggregateResult> aggFP = new List<AggregateResult>([
        SELECT SObjectType, min(Id) Id
        FROM FieldPermissions
        WHERE SObjectType IN :objectsToFix
            AND ParentId IN :modelPSIds
        GROUP BY SObjectType, Field
    ]);

Map<String, List<Id>> fieldsToFix = new Map<String, List<Id>>();

for (AggregateResult fpID : aggFP) {
    String tmpObj = (String) fpID.get('SObjectType');
    Id tmpID = (Id) fpID.get('Id');
    if (fieldsToFix.containsKey(tmpObj)) {
        fieldsToFix.get(tmpObj).add(tmpID);
    } else {
        fieldsToFix.put(tmpObj, new List <Id> { tmpID });
    }

}

for(String obj : objectsToFix){
    if (Limits.getQueries() > 90 || Limits.getQueryRows() > 40000) {
        System.debug('Apex batch limits reached. Please run again for next batch. exiting');
        break;
    }
    if (!fieldsToFix.containsKey(obj)) {
        System.debug('No permissionable field found in object ' + obj + ' - skipping');
        continue;
    }
    list<FieldPermissions>dup=[
        SELECT Id, SobjectType, Field
        FROM FieldPermissions
        WHERE SObjectType = :obj
            AND ParentId = :lpsGIU[0].Id
    ];

    list<FieldPermissions>fields=[SELECT SobjectType, Field FROM FieldPermissions WHERE Id IN :fieldsToFix.get(obj)];

    Integer count = 0;
    List<FieldPermissions> listOfFieldPermissions = new List<FieldPermissions>();
    for(FieldPermissions fp : fields){
        count++;
        FieldPermissions newFP = new FieldPermissions(
            Field = fp.Field,
            SobjectType = fp.SobjectType,
            ParentId = lpsGIU[0].Id,
            PermissionsRead = true
        );
        for(FieldPermissions d : dup){
            if (fp.Field == d.Field) {
                newFP.id=d.id ;
            }
        }
        listOfFieldPermissions.add(newFP);
    }
    try {
        upsert listOfFieldPermissions;
        System.debug('Completed successfully for object ' + obj + ' - granted access to ' + String.valueOf(count) + ' fields ');
    } catch(DmlException e) {
        System.debug('Error updating [' + obj + ']: ' + e.getMessage());
    }
}
```

### Option 2: Web-tools Script Builder

GRAX Web-tools can generate an FLS script that is scoped to a single-object at a time. This prevents many issues with Apex limits that may result from the larger script above while still making life easy for SFDC admins.

#### **Generating and Running a Script**

1. Navigate to `/web/tools` on your GRAX Application, or use the link at the top right of the `Settings` page
2. Select the `Missing Field Permissions` option
3. Select the `Show Apex Script` option for the intended object
4. Copy the generated script to your clipboard
5. Open the [Salesforce Developer Console](https://help.salesforce.com/s/articleView?id=sf.code_dev_console_opening.htm\&type=5)
6. Open the `Debug` menu
7. Select `Open Execute Anonymous Window` (or press `CTRL + E`)
8. Copy the script below into the `Enter Apex Code` dialog
9. Select the `Open Log` checkbox
10. Click `Execute`
11. In the `Execution Log` window, select the `Debug Only` checkbox
12. The script outputs the number of corrected fields in the last log line.

Repeat the steps above for each necessary object.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://documentation.grax.com/other/permissions-and-access/integration-user/scripts.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
