I have a spreadsheet that I owner and I have 10 users with editor permission
as there are quite a lot of cells to unlock or lock, it might be best to lock everything first
and unlock the ones that they can safely use without accidentally editing a formula incorrectly
now I'm just guessing what the best solution would be
I would like to avoid that users is deleted
if it matters then no one is in a group
these would be the ones that the editors can edit
['B3:U27', 'W3:AP27', 'E29:E31', 'I29:I31', 'M29:M31', 'Q29:Q31', 'U29:U31', 'Z29:Z31', 'AD29:AD31', 'AH29:AH31', 'AL29:AL31', 'AP29:AP31', 'B29', 'F29', 'J29', 'N29', 'R29', 'W29', 'AA29', 'AE29', 'AI29', 'AM29', 'C29', 'G29', 'K29', 'O29', 'S29', 'X29', 'AB29', 'AF29', 'AJ29', 'AN29', 'D29', 'H29', 'L29', 'P29', 'T29', 'Y29', 'AC29', 'AG29', 'AK29', 'AO29', 'B31', 'F31', 'J31', 'N31', 'R31', 'W31', 'AA31', 'AE31', 'AI31', 'AM31', 'C31', 'G31', 'K31', 'O31', 'S31', 'X31', 'AB31', 'AF31', 'AJ31', 'AN31', 'D31', 'H31', 'L31', 'P31', 'T31', 'Y31', 'AC31', 'AG31', 'AK31', 'AO31', 'B33:C33', 'F33:G33', 'J33:K33', 'N33:O33', 'R33:S33', 'W33:X33', 'AA33:AB33', 'AE33:AF33', 'AI33:AJ33', 'AM33:AN33' ,'D33:E33', 'H33:I33', 'L33:M33', 'P33:Q33', 'T33:U33', 'Y33:Z33', 'AC33:AD33', 'AG33:AH33', 'AK33:AL33', 'AO33:AP33'];
everything else can be locked
will 1 or 2 extra sheets be created each day and will this apply to all sheets from now on?
does it matter that already have a few sheets with manually protection (without a script)?
users will be notified of this
or is it all just happening in the background?
UPDATE:
I found the right script to protect the page and unlock the range
and it works perfectly
link
function testProtect() {
var sheet = SpreadsheetApp.getActiveSheet();
var protection = sheet.protect().setDescription('Sample protected sheet');
var unprotected = sheet.getRange('B3:I27');
protection.setUnprotectedRanges([unprotected]);
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
but there were two things I couldn't figure out
how can I apply it to all sheets and add more cells and ranges?
because if I add another range it gives an error
var unprotected = sheet.getRange('B3:I27','F29:I29');
Exception: B3:I27 cannot be converted to int type (line 4 in the "Code" file)
thanks in advance for any help!
If I understand your post correctly, here's your goal:
Create a script to lock your sheet and only allow specific ranges to be editable for the users with edit access.
Apply that script to all of your sheets on your spreadsheet file.
Recommended Solution:
You can refer to this sample script below where it locks your sheet and only unlock specific ranges you setup.
Sample script
[UPDATED]
function main(){ //Main function to run
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var disregard = ["Sheet3","Sheet4","Sheet5"]; //ADD SHEET NAMES HERE THAT YOU WANT TO BE DISREGARDED
for(var x=0; x<sheets.length; x++){
if(disregard.some(data => sheets[x].getName().includes(data))){
//E.g. Disregard any sheet names added on the "disregard" array
}else{
unlockCertainRanges(sheets[x]);
}
}
}
function unlockCertainRanges(currentSheet){ //Function to unlock certain ranges on your spreadshseet
var sheet = currentSheet;
// Remove all range protections in the spreadsheet
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
var protection = sheet.protect();
//restrict editors to owner
protection.getRange().getA1Notation();
var eds = protection.getEditors();
protection.removeEditors(eds);
//set unprotected ranges
var ranges = protection.getUnprotectedRanges();
var data = ["A1:A5","B6:B10","C11:C15"]; // ADD YOUR RANGES HERE
data.forEach(res => { //LOOPS INTO EVERY ARRAY CONTAINING SPECIFIC RANGES
ranges.push(sheet.getRange(res));
protection.setUnprotectedRanges(ranges); //REMOVES THE PROTECTION ON THE RANGE
});
}
Note:
Borrowed a snippet of script to unlock specific ranges from How to protect a sheet then unprotect specific cells as reference.
Result:
Sample Sheet
All cells are locked except the ranges "A1:A5","B6:B10" & "C11:C15" (contains the "Unlock" word for visibility)
Other cells are locked
Unlocked range cells are editable
Related
I have a spreadsheet that I owner and I have 10 users with editor permission
as there are quite a lot of cells to unlock or lock, it might be best to lock everything first
and unlock the ones that they can safely use without accidentally editing a formula incorrectly
now I'm just guessing what the best solution would be
I would like to avoid that users is deleted
if it matters then no one is in a group
these would be the ones that the editors can edit
['B3:U27', 'W3:AP27', 'E29:E31', 'I29:I31', 'M29:M31', 'Q29:Q31', 'U29:U31', 'Z29:Z31', 'AD29:AD31', 'AH29:AH31', 'AL29:AL31', 'AP29:AP31', 'B29', 'F29', 'J29', 'N29', 'R29', 'W29', 'AA29', 'AE29', 'AI29', 'AM29', 'C29', 'G29', 'K29', 'O29', 'S29', 'X29', 'AB29', 'AF29', 'AJ29', 'AN29', 'D29', 'H29', 'L29', 'P29', 'T29', 'Y29', 'AC29', 'AG29', 'AK29', 'AO29', 'B31', 'F31', 'J31', 'N31', 'R31', 'W31', 'AA31', 'AE31', 'AI31', 'AM31', 'C31', 'G31', 'K31', 'O31', 'S31', 'X31', 'AB31', 'AF31', 'AJ31', 'AN31', 'D31', 'H31', 'L31', 'P31', 'T31', 'Y31', 'AC31', 'AG31', 'AK31', 'AO31', 'B33:C33', 'F33:G33', 'J33:K33', 'N33:O33', 'R33:S33', 'W33:X33', 'AA33:AB33', 'AE33:AF33', 'AI33:AJ33', 'AM33:AN33' ,'D33:E33', 'H33:I33', 'L33:M33', 'P33:Q33', 'T33:U33', 'Y33:Z33', 'AC33:AD33', 'AG33:AH33', 'AK33:AL33', 'AO33:AP33'];
everything else can be locked
will 1 or 2 extra sheets be created each day and will this apply to all sheets from now on?
does it matter that already have a few sheets with manually protection (without a script)?
users will be notified of this
or is it all just happening in the background?
UPDATE:
I found the right script to protect the page and unlock the range
and it works perfectly
link
function testProtect() {
var sheet = SpreadsheetApp.getActiveSheet();
var protection = sheet.protect().setDescription('Sample protected sheet');
var unprotected = sheet.getRange('B3:I27');
protection.setUnprotectedRanges([unprotected]);
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
but there were two things I couldn't figure out
how can I apply it to all sheets and add more cells and ranges?
because if I add another range it gives an error
var unprotected = sheet.getRange('B3:I27','F29:I29');
Exception: B3:I27 cannot be converted to int type (line 4 in the "Code" file)
thanks in advance for any help!
If I understand your post correctly, here's your goal:
Create a script to lock your sheet and only allow specific ranges to be editable for the users with edit access.
Apply that script to all of your sheets on your spreadsheet file.
Recommended Solution:
You can refer to this sample script below where it locks your sheet and only unlock specific ranges you setup.
Sample script
[UPDATED]
function main(){ //Main function to run
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var disregard = ["Sheet3","Sheet4","Sheet5"]; //ADD SHEET NAMES HERE THAT YOU WANT TO BE DISREGARDED
for(var x=0; x<sheets.length; x++){
if(disregard.some(data => sheets[x].getName().includes(data))){
//E.g. Disregard any sheet names added on the "disregard" array
}else{
unlockCertainRanges(sheets[x]);
}
}
}
function unlockCertainRanges(currentSheet){ //Function to unlock certain ranges on your spreadshseet
var sheet = currentSheet;
// Remove all range protections in the spreadsheet
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
var protection = sheet.protect();
//restrict editors to owner
protection.getRange().getA1Notation();
var eds = protection.getEditors();
protection.removeEditors(eds);
//set unprotected ranges
var ranges = protection.getUnprotectedRanges();
var data = ["A1:A5","B6:B10","C11:C15"]; // ADD YOUR RANGES HERE
data.forEach(res => { //LOOPS INTO EVERY ARRAY CONTAINING SPECIFIC RANGES
ranges.push(sheet.getRange(res));
protection.setUnprotectedRanges(ranges); //REMOVES THE PROTECTION ON THE RANGE
});
}
Note:
Borrowed a snippet of script to unlock specific ranges from How to protect a sheet then unprotect specific cells as reference.
Result:
Sample Sheet
All cells are locked except the ranges "A1:A5","B6:B10" & "C11:C15" (contains the "Unlock" word for visibility)
Other cells are locked
Unlocked range cells are editable
I am needing to range protect cells on a sheet based on the name in the cell. I can obtain a persons email address from their name and protect the cell so only they can edit it.
It seems to be taking a very long time to add a person to the range protection. I have used the logger to find out what is taking so long and it appears protection.addEditor() is taking 27700ms and protection.removeEditors() is taking 21904ms. Is this normal?
The workbook is shared with a set group of about 30 people, there are about 60 sheets and the workbook contains about 300,000 cells in total.
Any ideas why this is taking so long?
I am getting an Error: Exception: Service Spreadsheets timed out while accessing document with id .... This does not happen every time the script is run, but when it does it always happens at the point where I am protecting a cell. I run an overnight process to look for new entries and protect those cells so only the named person can edit. It is used as a shift booking system.
I was hoping it might be possible to protect all the cells that need protecting in one go for each sheet, but I cannot find anything about how to do this.
function protectActiveCell() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var bookCell = sheet.getCurrentCell();
var name = bookCell.getValue();
var person = getPersonFromName(name);
var email = person.email;
*emphasized text*var others = getOtherUsersEmails(email);
removeCellProtection(bookCell);
var protection = bookCell.protect();
SpreadsheetApp.flush();
protection.addEditor(email);
protection.removeEditors(others);
SpreadsheetApp.flush();
}
function removeCellProtection(cell) {
// Remove range protections from specific cell.
var sheet = cell.getSheet();
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.getRange().getA1Notation() == cell.getA1Notation()) {
protection.remove();
SpreadsheetApp.flush();
}
}
}
OK, so my main question here is if I can reduce the time it takes for this script below to run--it takes on average 8 minutes, 5-6 of which is just from copying sheets into another spreadsheet and pasting their original display values over them.
The purpose of this is to have vendor sheets from four different spreadsheets totaled in alphabetical order for sending as-is or for printing. I already researched trying do use PDFs instead, but have not been able to find a way to be able to print in a specific order with the resources I have--which do not include Adobe premium or access to printers for something like powershell scripts, which I do not know anyway. (Printing a folder of files does not actually print in sequential order, unfortunately, so generating PDFs of each sheet does not give me an option to print in alphabetical order.)
So, my workaround is to get an array of the four source spreadsheets, loop through those with another loop that goes through each sheet, and for each sheet make a copy to the merge spreadsheet, and then get and paste over each sheet with the display values as there would otherwise be issues with formulas not referencing. Then it calls other functions to rename the sheets without "Copy of " on them and then to place them in alphabetical order. For ongoing use, it starts by deleting all the old sheets except for an Index sheet from the merged spreadsheet.
Is there any way to reduce the number of calls? I looked into while loops, but it's different in that a lot of the "data" I'm moving is actual entire sheets, and I need their formatting as well. I considered just inserting the same number of sheets as I would be copying, and then repeating copying the same format which they all have, but that hits into an issue with the names--there can sometimes be duplicate named sheets between the source spreadsheets which have to be allowed in, and copying in just makes additional ones have a number at the end. That is fine, but I cannot set the names of the sheets before they are in the merged spreadsheet due to this, unless I can somehow check for duplicate sheet names and add "1", "2", etc, to them to allow them in.
Is the time running this just inevitable for this process, or can I speed it up?
//https://stackoverflow.com/questions/58834873/copy-google-sheet-values-to-another-google-spreadsheet-and-create-new-sheet-with?rq=1
//https://stackoverflow.com/questions/36758479/google-apps-script-to-iterate-through-a-list-of-spreadsheet-ids-and-copy-range
//Global variables. Runs from the merging spreadsheet, and the IDs of the four source Vendor spreadsheets
var mergeSpreadsheet = SpreadsheetApp.getActive();
var indexSheet = "Index"; //global for alphabetzing script
var monthly732 = '1TLH8HencpyH-4pDkQ1LetTErRxqYjh4gYC0XDdQxSVM'
var monthly827 = '19UfhUAvpFi0UJBF-rQoc4LWcL20-79nRltbSL-Wpj0A'
var quarterly732 = '1BRhoO_GcEoBmV_SoaV2xkw9BjgasAX3CorKxgWuEd2I'
var quarterly827 = '1JaAQtRIiCaQjO_A5S0p-VjHk8LUXExmqOYo75LxWf58'
//main function
function mergeTest2(){
deleteAllSheets(); //calls function at end of script to delete old sheets from merged spreadsheet
//Array of source spreadsheets for looping through
var idList = [monthly732, monthly827, quarterly732, quarterly827];
for (var i = 0; i < idList.length; i++){
//get sheets from each source spreadsheet
var allsheets = SpreadsheetApp.openById(idList[i]).getSheets();
//For each spreadsheet, iterate through sheets except for Index and Template
// Stop iteration execution if the condition is meet.
for(var s in allsheets){
var sheet = allsheets[s];
if(
(sheet.getName() == "Index") ||
(sheet.getName() == "Template") ||
(sheet.getName() == "Totals")
) continue;
//For each sheet, copyTo merged spreadsheet, get original's display values and paste them on the copy
//Using copyTo to get format of sheet, and allow for duplicate sheet names added
var mergeSheet = sheet.copyTo(mergeSpreadsheet);
//Getting display values to override formulas to avoid REF errors
var sValues = sheet.getDataRange().getDisplayValues();
mergeSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues);
} //allsheets, end of for-loop for sheets within a spreadsheet
} //end for-loop of array of spreadsheets
//Get numbers of sheets from each spreadsheet for comparing to make sure all applicable ones were copied
//formulas set in Index page for comparing applicable sheets from sources (Vendors only) to make sure they equal merged Vendor sheets at the end
var index_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(indexSheet);
index_sheet.getRange("C2").setValue(SpreadsheetApp.openById(monthly732).getNumSheets());
index_sheet.getRange("D2").setValue(SpreadsheetApp.openById(monthly827).getNumSheets());
index_sheet.getRange("E2").setValue(SpreadsheetApp.openById(quarterly732).getNumSheets());
index_sheet.getRange("F2").setValue(SpreadsheetApp.openById(quarterly827).getNumSheets());
index_sheet.getRange("B2").setValue(mergeSpreadsheet.getNumSheets());
//Loggers used for testing, replace with getNumSheets above in final
Logger.log(SpreadsheetApp.openById(monthly732).getNumSheets());
Logger.log(SpreadsheetApp.openById(monthly827).getNumSheets());
Logger.log(SpreadsheetApp.openById(quarterly732).getNumSheets());
Logger.log(SpreadsheetApp.openById(quarterly827).getNumSheets());
Logger.log(mergeSpreadsheet.getNumSheets());
slicerOfNames(); //call slicer function below for removing "Copy of " from sheet names.
sortSheetsByName(); //call function to put sheets in alphabetical order
} //end mergeTest2 main function
//Function to get sheet names except for Index, or that all have "Copy of " in name, and slice(8)
function slicerOfNames(){
mergeSpreadsheet.getSheets().forEach(function(sheet) {
var sheetName = sheet.getSheetName();
if (sheetName.indexOf("Copy of ") == -1) {
Logger.log(sheetName);
} else {
sheet.setName(sheetName.slice(8));
} //end if/else
}) //end function(sheet)
} //end slicer function
//Function for alphabetical ordering of sheets within merged spreadsheet
function sortSheetsByName() {
var aSheets = new Array();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var allsheets = ss.getSheets();
for (var s in allsheets)
{
var ss = SpreadsheetApp.getActive();
var sheet = allsheets[s];
if(
(sheet.getName() == indexSheet)
) continue;
aSheets.push(ss.getSheets()[s].getName());
}
if(aSheets.length)
{
ss.getSheetByName(indexSheet).activate()
ss.moveActiveSheet(1)
aSheets.sort();
for (var i = 0; i < aSheets.length; i++)
{
var theSheet = ss.getSheetByName(aSheets[i]);
if(theSheet.getIndex() != i + 2){
ss.setActiveSheet(theSheet);
ss.moveActiveSheet(i + 2);
} //end if statement
} //end for-loop
} // end if(aSheets.length)
}//end alphabetization function
//Function to delete old sheets from merged spreadsheet at the beginning of the script
function deleteAllSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var result = SpreadsheetApp.getUi().alert("This will delete all sheets except the Index, are you sure?", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if(result === SpreadsheetApp.getUi().Button.OK) {
var sheets = ss.getSheets();
for (i = 0; i < sheets.length; i++) {
switch(sheets[i].getSheetName()) {
case "Index":
break;
default:
ss.deleteSheet(sheets[i]);}}
} else {
SpreadsheetApp.getActive().toast("Sheets not deleted");
}
} //end delete sheets function
In your code, it looks you set values of disjoint ranges five separate times, which is very expensive. You could combine these into one line like combined_range.setValues(2D_array). If you are worried about overwriting any existing data, use combined_range.getValues(), and then manipulate the returned 2D array using Apps Script prior to setting.
Following a similar philosophy, logging can be made much more efficient as well; in general, consider implementing a hash map to store and organize the results of frequent spreadsheet calls. Alternatively, variables can also otherwise be used to condense, hasten, and improve overall readability.
I've taken the information from here
to create a script that will protect a range of cells within sheets from being edited but also excludes areas where a user can enter data. My script looks like this.
function myFunction() {
// Protect the active sheet except B2:C5, then remove all other users from the list of editors.
var sheet = SpreadsheetApp.getActiveSheet();
var protection = sheet.protect().setDescription('2016-07-21 Material Request Form Template');
var unprotected = sheet.getRange('C9:D9');
protection.setUnprotectedRanges([unprotected]);
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
On the line that reads var unprotected = sheet.getRange('C9:D9'); this will indeed unlock this range as expected within the protected sheet but I also have other ranges within this document that I'd like to restrict. How can I enter or modify this line so that I can lock out multiple ranges i.e. C9:D9 and A12:E12 and A24:K24
If I simply copy this line and paste it with a new cell range, it overwrites the previous unprotected range and activates the new line I just pasted.
Thank you.
For multiple unprotected ranges you need to pass all of the ranges as the array argument in one call:
var range1 = sheet.getRange("A1:A6");
var range2 = sheet.getRange("B1:B6");
protection.setUnprotectedRanges([range1, range2]);
Your question seems to switch and you appear to end up asking how to restrict access to multiple ranges, rather than unprotecting them? In order to do this, protect the whole sheet and then unprotect the relevant ranges to achieve what you need.
I'm trying to permanently lock/protect certain cells on 14 different sheets (1 hidden from the workers for formula stuff). I have them all locked and no one can edit if I add them to it as an editor. But it is the template, I make copies of it for each client (and new clients) for the staff. The staff that works on the sheet and the employees are only allowed to edit certain cells for the work they do.
The problem is if I have Workbook1 with X cells locked on the different sheets, make a copy, rename it to Workbook - Client#ID, then add them employees John and Jane, who will be working on this client, as editors; they can now edit every cell, including the protected ones (they get added as editors to the protected cells too). It doesn't do this on the original, it only happens to the copy made of the template. I then have to go through all 13 sheets and remove them from the protected cells.
I'm trying to quickly remove them automatically with a script add-on that I want to turn into a button or something later...
Or is there a better way to fix this bug?
Google has an example of removing users and keeping sheet protected and I have tried to add in what I need to make it work, but it doesn't do anything when I run the test as an add-on for the spreadsheet. I open a new app script project from my spreadsheet and enter in the example code from google
// Protect the active sheet, then remove all other users from the list of editors.
var sheet = SpreadsheetApp.setActiveSheet(January);
var protection = sheet.protect().setDescription('Activity Log');
var unprotected = sheet.getRange('A2:N7');
protection.setUnprotectedRanges([unprotected]);
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
For this you can write a script function to set the protection ranges and add editors for the sheets as well.
Please check the sample apps script code to add protection for a range in a sheet below:
function addProtection()
{
// Protect range A1:B10, then remove all other users from the list of editors.
var ss = SpreadsheetApp.getActive();
var range = ss.getRange('A1:B10');
var protection = range.protect().setDescription('Sample protected range');
// var me = Session.getEffectiveUser();
// array of emails to add them as editors of the range
protection.addEditors(['email1','email2']);
// array of emails to remove the users from list of editors
protection.removeEditors(['email3','email4']);
}
Hope that helps!
Adding on #KRR's answer.
I changed the script to be dynamic.
function setProtection() {
var allowed = ["example#gmail.com,exmaple2#gmail.com"];
addProtection("Sheet1","A1:A10",allowed);
}
function editProtection(sheetname,range,allowed,restricted) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetname);
var range = sheet.getRange(range);
//Remove previous protection on this range
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0;i<protections.length;i++) {
if (protections[i].getDescription() === sheetname + range){
protections[i].remove();
}
}
//Set new protection
var protection = range.protect().setDescription(sheetname + range);
// First remove all editors
protection.removeEditors(protection.getEditors());
// Add array of emails as editors of the range
if (typeof(allowed) !== "undefined") {
protection.addEditors(allowed.toString().split(","));
}
}
You can add as many options as you want and make them run onOpen. Set your variable and call editProtection as many times as you need.
You can get the emails dynamically from spreadsheet editors.
Also you might want to add another script to protect the whole sheet and set you as the owner.
Hope this helps.
It MUST be run as SCRIPT and NOT as an add-on.
If you have already locked your sheets and made your exceptions you can easily use Google's example code. We can use a for loop to find all the sheets and names. Then add a button to the script to load at start.
function FixPermissions() {
// Protect the active sheet, then remove all other users from the list of editors. Get all sheets in the workbook into an array
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
//Use a for loop to go through each sheet and change permissions and label it according to the name of the sheet
for (var i=0; i < sheets.length; i++) {
var name = sheets[i].getSheetName()
var protection = sheets[i].protect().setDescription(name);
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
}
//A special function that runs when the spreadsheet is open, used to add a custom menu to the spreadsheet.
function onOpen() {
var spreadsheet = SpreadsheetApp.getActive();
var menuItems = [
{name: 'Fix Permission', functionName: 'FixPermissions'}
];
spreadsheet.addMenu('Permissions', menuItems);
}
Now in the menu bar you will see a new item when you reload/load the spreadsheet labeled Permissions