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.

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

Prepare a sheet that lists the access permissions for each file.
For details on how to list access permissions, please refer to [this article].

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

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)

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

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

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.”

After writing the script, save it with a name.
(Example: “Bulk Access Permission Update”)

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.”

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.
-
Streamline Business Card Digitization with OCR and Google Apps Script: Save Time on Spreadsheet Data Entry
-
Bulk Delete Files in Google Drive with Google Apps Script: Organize with Spreadsheets
-
How to Efficiently Organize Business Card Data with ChatGPT API: Leveraging Google Sheets and AI
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
Comments