Manage and Modify Spreadsheet Permissions in Bulk with Google Apps Script: The Update Guide

In the previous article, we introduced how to list the access permissions of spreadsheet files.

This time, we’ll explain how to use the retrieved information to modify access permissions for multiple files in bulk.

When managing multiple files in a business setting, manually updating the permissions for each file can be time-consuming. However, with this method, you can make changes to permissions all at once, saving both time and effort.

TOC

Example Output

Listing Access Permissions (Previous Article)

Bulk Modification of Access Permissions (This Article)

Using the input data in the spreadsheet, this guide demonstrates how to use Google Apps Script to update the access permissions for each file.

You can select the files that require changes and configure settings to grant or remove viewing or editing permissions for specific users.

Steps

Preparing the Spreadsheet

STEP
Open the Spreadsheet

Prepare a sheet that lists the access permissions for each file.

For details on how to list access permissions, please refer to [this article].

STEP
Mark Files for Modification

By checking the boxes in the “Change Target” column, you can specify which files will be targeted for access permission updates.

STEP
Select New Permissions

Choose the desired type of access permission from the dropdown list.

The dropdown list is generated during the previous execution of the Google Apps Script.

  • Restricted
  • Anyone with the link (View)
  • Anyone with the link (Comment)
  • Anyone with the link (Edit)
STEP
Remove or Add Viewers and Editors

Enter email addresses in the corresponding columns:

  • Remove Viewers
  • Remove Editors
  • Add Viewers
  • Add Editors

If there are multiple email addresses, enter them separated by commas.

(Example: user1@example.com, user2@example.com)

To modify the permissions of email addresses already registered as restricted viewers or editors, you must first remove the existing permission and then re-add the address with the desired permission.




For example, to change user1@example.com from viewer permission to editor permission:

Enter user1@example.com in the “Remove Viewers” column.
Enter the same email address in the “Add Editors” column.

By following this process, the user’s permissions will be updated correctly.

Run the Script

STEP
Open Apps Script Editor

Open a Google Spreadsheet and click on “Extensions” in the menu, then “Apps Script” to open the Apps Script editor.

STEP
Create the Script

Since the default function myFunction() {} is present, delete it and replace it with the script below.

It’s a long script, but there’s a copy button in the top-right corner of the code block.

function updateAccessPermissions() {
  const sheetName = 'Access Management';
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  const lastRow = sheet.getLastRow();
  
  for (let row = 2; row <= lastRow; row++) {
    const checkCell = sheet.getRange(row, 7); // Checkbox to select target
    const newPermission = sheet.getRange(row, 8).getValue(); // New permissions to apply
    const fileUrl = sheet.getRange(row, 2).getFormula().match(/"(.*?)"/)[1]; // Extract file URL from hyperlink

    if (checkCell.isChecked() && newPermission) {
      const fileId = getFileIdFromUrl(fileUrl);
      const file = DriveApp.getFileById(fileId);

      // Update access permissions based on the selected option
      if (newPermission === 'Anyone with the link (View)') {
        file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
      } else if (newPermission === 'Anyone with the link (Comment)') {
        file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.COMMENT);
      } else if (newPermission === 'Anyone with the link (Edit)') {
        file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT);
      } else if (newPermission === 'Restricted') {
        file.setSharing(DriveApp.Access.PRIVATE, DriveApp.Permission.NONE); // Set to restricted
      }

      // Remove viewers and editors based on email addresses in specific columns
      let existingViewers = sheet.getRange(row, 5).getValue().split(',').map(email => email.trim()).filter(email => email);
      let existingEditors = sheet.getRange(row, 6).getValue().split(',').map(email => email.trim()).filter(email => email);

      const removeViewers = sheet.getRange(row, 9).getValue().split(',').map(email => email.trim());
      removeViewers.forEach(email => {
        if (email) {
          try {
            file.removeViewer(email); // Remove as viewer
            existingViewers = existingViewers.filter(e => e !== email); // Update viewer list
          } catch (e) {
            Logger.log(`Failed to remove ${email} as viewer: ${e.message}`);
          }
        }
      });

      const removeEditors = sheet.getRange(row, 10).getValue().split(',').map(email => email.trim());
      removeEditors.forEach(email => {
        if (email) {
          try {
            file.removeEditor(email); // Remove as editor
            existingEditors = existingEditors.filter(e => e !== email); // Update editor list
          } catch (e) {
            Logger.log(`Failed to remove ${email} as editor: ${e.message}`);
          }
        }
      });

      // Add viewers and editors based on input in specific columns
      const addViewers = sheet.getRange(row, 11).getValue().split(',').map(email => email.trim());
      addViewers.forEach(email => {
        if (email && !existingViewers.includes(email)) {
          file.addViewer(email); // Add as viewer
          existingViewers.push(email); // Update viewer list
        }
      });

      const addEditors = sheet.getRange(row, 12).getValue().split(',').map(email => email.trim());
      addEditors.forEach(email => {
        if (email && !existingEditors.includes(email)) {
          file.addEditor(email); // Add as editor
          existingEditors.push(email); // Update editor list
        }
      });

      // Update the sheet with the latest viewer and editor lists
      sheet.getRange(row, 5).setValue(existingViewers.filter(email => email).join(', '));
      sheet.getRange(row, 6).setValue(existingEditors.filter(email => email).join(', '));

      // Update the "Current Permissions" column
      const updatedPermission = translatePermission(file.getSharingAccess(), file.getSharingPermission());
      sheet.getRange(row, 3).setValue(updatedPermission);

      // Add a timestamp in the last column
      sheet.getRange(row, 13).setValue(new Date());
      
      // Clear data in columns H–L
      sheet.getRange(row, 8, 1, 5).setValue('');
      
      // Uncheck the checkbox
      checkCell.setValue(false);
    }
  }
}

// Helper function to extract the file ID from a file URL
function getFileIdFromUrl(fileUrl) {
  const regex = /[-\w]{25,}/;
  const match = fileUrl.match(regex);
  return match ? match[0] : null;
}

// Helper function to translate access and permission levels to readable format
function translatePermission(access, permission) {
  const accessMap = {
    [DriveApp.Access.ANYONE]: 'Anyone',
    [DriveApp.Access.ANYONE_WITH_LINK]: 'Anyone with the link',
    [DriveApp.Access.PRIVATE]: 'Restricted'
  };
  const permissionMap = {
    [DriveApp.Permission.VIEW]: 'View',
    [DriveApp.Permission.COMMENT]: 'Comment',
    [DriveApp.Permission.EDIT]: 'Edit'
  };

  // For restricted access, display only "Restricted"
  if (access === DriveApp.Access.PRIVATE) {
    return accessMap[access];
  } else {
    return `${accessMap[access] || 'Unknown'} (${permissionMap[permission] || 'Unknown'})`;
  }
}
Script Description
Main Function:updateAccessPermissions()
function updateAccessPermissions() {
  const sheetName = 'Access Management';
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  const lastRow = sheet.getLastRow();
  
  for (let row = 2; row <= lastRow; row++) {
    const checkCell = sheet.getRange(row, 7); // Checkbox to select target
    const newPermission = sheet.getRange(row, 8).getValue(); // New permissions to apply
    const fileUrl = sheet.getRange(row, 2).getFormula().match(/"(.*?)"/)[1]; // Extract file URL from hyperlink

    if (checkCell.isChecked() && newPermission) {
      const fileId = getFileIdFromUrl(fileUrl);
      const file = DriveApp.getFileById(fileId);

      // Update access permissions based on the selected option
      if (newPermission === 'Anyone with the link (View)') {
        file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
      } else if (newPermission === 'Anyone with the link (Comment)') {
        file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.COMMENT);
      } else if (newPermission === 'Anyone with the link (Edit)') {
        file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT);
      } else if (newPermission === 'Restricted') {
        file.setSharing(DriveApp.Access.PRIVATE, DriveApp.Permission.NONE); // Set to restricted
      }

      // Remove viewers and editors based on email addresses in specific columns
      let existingViewers = sheet.getRange(row, 5).getValue().split(',').map(email => email.trim()).filter(email => email);
      let existingEditors = sheet.getRange(row, 6).getValue().split(',').map(email => email.trim()).filter(email => email);

      const removeViewers = sheet.getRange(row, 9).getValue().split(',').map(email => email.trim());
      removeViewers.forEach(email => {
        if (email) {
          try {
            file.removeViewer(email); // Remove as viewer
            existingViewers = existingViewers.filter(e => e !== email); // Update viewer list
          } catch (e) {
            Logger.log(`Failed to remove ${email} as viewer: ${e.message}`);
          }
        }
      });

      const removeEditors = sheet.getRange(row, 10).getValue().split(',').map(email => email.trim());
      removeEditors.forEach(email => {
        if (email) {
          try {
            file.removeEditor(email); // Remove as editor
            existingEditors = existingEditors.filter(e => e !== email); // Update editor list
          } catch (e) {
            Logger.log(`Failed to remove ${email} as editor: ${e.message}`);
          }
        }
      });

      // Add viewers and editors based on input in specific columns
      const addViewers = sheet.getRange(row, 11).getValue().split(',').map(email => email.trim());
      addViewers.forEach(email => {
        if (email && !existingViewers.includes(email)) {
          file.addViewer(email); // Add as viewer
          existingViewers.push(email); // Update viewer list
        }
      });

      const addEditors = sheet.getRange(row, 12).getValue().split(',').map(email => email.trim());
      addEditors.forEach(email => {
        if (email && !existingEditors.includes(email)) {
          file.addEditor(email); // Add as editor
          existingEditors.push(email); // Update editor list
        }
      });

      // Update the sheet with the latest viewer and editor lists
      sheet.getRange(row, 5).setValue(existingViewers.filter(email => email).join(', '));
      sheet.getRange(row, 6).setValue(existingEditors.filter(email => email).join(', '));

      // Update the "Current Permissions" column
      const updatedPermission = translatePermission(file.getSharingAccess(), file.getSharingPermission());
      sheet.getRange(row, 3).setValue(updatedPermission);

      // Add a timestamp in the last column
      sheet.getRange(row, 13).setValue(new Date());
      
      // Clear data in columns H–L
      sheet.getRange(row, 8, 1, 5).setValue('');
      
      // Uncheck the checkbox
      checkCell.setValue(false);
    }
  }
}
  • This function updates file access permissions based on the state of the checkboxes in the list.
  • Columns H–L are reset after the process is complete, preparing the spreadsheet for the next set of inputs.
Utility Functions:getFileIdFromUrl()andtranslatePermission() 
// Helper function to extract the file ID from a file URL
function getFileIdFromUrl(fileUrl) {
  const regex = /[-\w]{25,}/;
  const match = fileUrl.match(regex);
  return match ? match[0] : null;
}
  • Extracts the file ID from a Google Drive file URL.
  • It uses a regular expression to identify the file ID within the URL.
// Helper function to translate access and permission levels to readable format
function translatePermission(access, permission) {
  const accessMap = {
    [DriveApp.Access.ANYONE]: 'Anyone',
    [DriveApp.Access.ANYONE_WITH_LINK]: 'Anyone with the link',
    [DriveApp.Access.PRIVATE]: 'Restricted'
  };
  const permissionMap = {
    [DriveApp.Permission.VIEW]: 'View',
    [DriveApp.Permission.COMMENT]: 'Comment',
    [DriveApp.Permission.EDIT]: 'Edit'
  };

  // For restricted access, display only "Restricted"
  if (access === DriveApp.Access.PRIVATE) {
    return accessMap[access];
  } else {
    return `${accessMap[access] || 'Unknown'} (${permissionMap[permission] || 'Unknown'})`;
  }
}
  • This function translates Google Drive access and permission levels into a human-readable format.

For example:

  • Access Levels:
    • Anyone
    • Anyone with the link
    • Restricted
  • Permission Levels:
    • View
    • Comment
    • Edit

It combines these levels to provide clear descriptions, such as “Anyone with the link (View)” or “Restricted.” If the access or permission is undefined, it returns “Unknown.”

STEP
Save the Script

After writing the script, save it with a name.

(Example: “Bulk Access Permission Update”)

STEP
Run the Script

Run the script.

If you’re running the script for the first time, you need to authorize it.

Therefore, press “Review Permissions.

Detailed Authorization Steps

Press “Advanced.”

Press “Go to Untitled project (Unsafe).”

After that, press “Allow.”

STEP
Access Permissions Updated

Columns A–F

After execution, the access permissions for the selected files are updated.
The spreadsheet information is also replaced with the new access permission statuses.

Columns G–M

Once the changes are completed, columns G–L are reset and cleared.
Column M is updated with a timestamp indicating the successful execution.

注意事項

Changes to Access Permissions May Take Time to Reflect

After running the script, there may be a delay before the changes to access permissions are reflected.

If the changes are not visible immediately, please wait a while and check the permissions again.

If No Timestamp is Added

If no timestamp appears, it is possible that the script did not execute successfully.

Check the spreadsheet for missing input, especially in column H (“New Permissions”).

Leaving this column blank may prevent the script from applying changes to viewer or editor email addresses.

Conclusion

In this article, we explained how to update file access permissions in Google Drive in bulk using a Google Spreadsheet.

This method reduces the effort required to manage sharing settings for multiple files, saving you time and improving efficiency.

Our company offers support for improving work efficiency through the use of Google Apps Script.
If you need assistance with Google Apps Script customization or error resolution, please feel free to contact us.
We are fully committed to supporting your business improvements.

Contact us here

Let's share this post !

Comments

To comment

TOC