0

I'm using a code to duplicate a template sheet with multiple range protections within it,

Currently, I'm running the script to create one by one the new tabs. Can anyone help me with the following script to be able to duplicate the template many times at once (Example create from Template Sheet the following tabs: A,B,C,D,E,F) in one go:

Script

function duplicateSheetWithProtections() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); 
sheet = ss.getSheetByName('Template');
sheet2 = sheet.copyTo(ss).setName('A'); 
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var p = protections[i];
var rangeNotation = p.getRange().getA1Notation();
var p2 = sheet2.getRange(rangeNotation).protect();
p2.setDescription(p.getDescription());
p2.setWarningOnly(p.isWarningOnly());
if (!p.isWarningOnly()) {
  p2.removeEditors(p2.getEditors());
  p2.addEditors(p.getEditors());
}
}
}

Thank you for your help

Nabnub
  • 953
  • 6
  • 15

1 Answers1

4

How about this modification? I think that you can achieve what you want using Sheets API. The flow of this sample script is as follows.

When you use this script, please enable Sheets API at Advanced Google Services and API console. You can see about how to enable Sheets API at here.

Flow:

  1. Set copied sheet names. For example, those are ["A", "B", "C",,]. This is from your question.
  2. Copy template sheet using the sheet names.
  3. Retrieve protected ranges from Template sheet using Sheets API.
  4. Create request body.
  5. Set protected ranges to copied sheets using Sheets API.

By this flow, the protected ranges of Template sheet can be copied to the all copied sheets by only one API call.

Modified script:

function duplicateSheetWithProtections() {
  var sheetNames = ["A", "B"]; // Please set copied sheet names here.

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var spreadsheetId = ss.getId();
  var sheet = ss.getSheetByName('Template');

  // Copy template sheet.
  var copiedSheetIds = sheetNames.map(function(e) {return sheet.copyTo(ss).setName(e).getSheetId()});

  // Retrieve protected ranges from Template sheet.
  var sheets = Sheets.Spreadsheets.get(spreadsheetId).sheets;
  var templateSheet = sheets.filter(function(e) {return e.properties.title == "Template"});
  var protectedRanges = templateSheet[0].protectedRanges;

  // Create request body.
  var resources = copiedSheetIds.map(function(e) {
    return protectedRanges.map(function(f) {
      var obj = JSON.parse(JSON.stringify(f));
      delete obj.protectedRangeId;
      if (obj.warningOnly) delete obj.editors;
      obj.range.sheetId = e;
      return {"addProtectedRange": {"protectedRange": obj}};
    });
  });
  resources = Array.prototype.concat.apply([], resources);

  // Set protected ranges to copied sheets
  Sheets.Spreadsheets.batchUpdate({"requests": resources}, spreadsheetId);
}

References:

If I misunderstand your question, please tell me. I would like to modify it.

Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • Tanaike it works perfectly THANK YOU !! Note: After enabling the Sheets API we may need to wait few until it works otherwise we get an error message. Do you think we could modify the script to add a whole sheet protection at the same time ? – Nabnub Oct 16 '18 at 04:37
  • @Nabnub Thank you for replying. I'm glad your issue was solved. At ``Sheets.Spreadsheets.batchUpdate``, each request is run in order. So the asynchronous process cannot be done. I'm really sorry for this specification. – Tanaike Oct 16 '18 at 04:42
  • Thank you for your help. I'm just trying to reduce the manual work. There is an Add-on (Bulk Sheet Manager ) that can help me doing that. This is linked to another project that I'm still searching a solution for, I think you have tried last time to understand my question. Please see my profile (Question: How to remove whole sheet protection of specific tabs for specific editors using a script?). I worked on other scripts since that time and still didn't solved this one. ありがとう – Nabnub Oct 16 '18 at 04:52
  • @Nabnub Welcome. Thank you, too. I think that when you want to remove the protected range, you can use DeleteProtectedRangeRequest of ``Sheets.Spreadsheets.batchUpdate``. https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#deleteprotectedrangerequest But that is not for this question. I'm sorry for this situation. – Tanaike Oct 16 '18 at 04:56
  • Perhaps my question was not clear. Thank you for your support. I'm referring to this question here (https://stackoverflow.com/questions/52691817/how-to-remove-whole-sheet-protection-of-specific-tabs-for-specific-editors-using). If by any chance you could have a look at it. – Nabnub Oct 16 '18 at 05:05
  • @Nabnub Can you change the space of discussion to [the question](https://stackoverflow.com/questions/52691817/how-to-remove-whole-sheet-protection-of-specific-tabs-for-specific-editors-using), because your latest comment is not for this question? – Tanaike Oct 16 '18 at 05:10
  • thank for your follow up, I got an error when trying to run the script on a copy of the spreadsheet, then I remembered that I need to Enable the Sheet API and go through the steps that you've mentioned. That was useful compared to my initial script, but If I need to duplicate this documents to many folders, does it mean that I will need to enable every time the Sheet API for each new document ? which might be time consuming ...My goal was to speed the task because I will create many spreadsheets within many folders. Thank you for any suggestion – Nabnub Oct 19 '18 at 10:37
  • @Nabnub If you want to use the container-bound script of Spreadsheet by copying Spreadsheet, it is required to enable Sheets API every copied Spreadsheet. If you don't want to enable it every time, please think of the use of Add-on. https://developers.google.com/apps-script/guides/sheets#add-ons_for_google_sheets If this is not what you want, I'm sorry. – Tanaike Oct 19 '18 at 12:12
  • Hi @Tanaike, This was exact thing I was looking for. However, when I apply the batchUpdate, I get error - GoogleJsonResponseException: API call to sheets.spreadsheets.batchUpdate failed with error: Invalid requests[0].addProtectedRange: The range you're trying to exclude must be within "A". Any thoughts on that? – SurajS May 26 '21 at 16:05
  • Update - My protection was whole sheet except some ranges, it failed. When I tried adding protection to couple of ranges, it failed – SurajS May 26 '21 at 16:15
  • @SurajS About your question, unfortunately, I cannot image your current situation. But I would like to support you. So, can you post it as new question by including more information? By this, it will help users including me think of the solution. If you can cooperate to resolve your issue, I'm glad. Can you cooperate to do it? – Tanaike May 27 '21 at 01:23
  • @Tanaike https://stackoverflow.com/questions/67709175/google-sheets-scripts-copy-whole-sheet-protection – SurajS May 27 '21 at 07:48
  • @SurajS Thank you for replying of `@Tanaike https://stackoverflow.com/questions/67709175/google-sheets-scripts-copy-whole-sheet-protection`. I'm glad your issue was resolved. – Tanaike May 28 '21 at 00:20