The following Google Apps Script is designed to bulk create Google Drive folders along with a sub-folder from data given in a Google Sheet (eg to name the folders and add permissions).
This tool and blog post is largely a continuation of this one for bulk creating Google Drive folders. The main difference being that there is an extra column to provide the name of your sub-folder. Note that the tool will try to create a sub-folder regardless of what is entered - as I was just aiming to create a version for the many requests I got from the previous blog post from people who wanted a sub-folder.
Bulk create Google Drive folders from a Sheet of data |
Concatenation
Create those useful descriptive folder/file names so items are easier to search for in the future. Concatenate will let you combine values that may exist in different columns in another spreadsheet for example, or take those folder names and prepend/append words around them. Concatenate guide webpage here.
Download
Download the Bulk create Google Drive folders with a sub-folder here. Please use 'File' > 'Make a copy' for your own version.
/* | |
This overall script is designed to bulk create Google Folders from data within a Google Sheet | |
and add relevant permissions (if applicable). | |
*/ | |
function getSpreadsheetData() { | |
// Log starting of the script | |
logEvent('Script has started'); | |
// get current spreadsheet | |
var ss = SpreadsheetApp.getActiveSpreadsheet(); | |
// display Toast notification | |
ss.toast('Script has now started', 'Start'); | |
// get TimeZone | |
var timeZone = ss.getSpreadsheetTimeZone(); | |
// get Config sheet | |
var configSheet = ss.getSheetByName('Config'); | |
// get Parent Google Folder ID for storing created Folders in | |
var destinationFolderId = configSheet.getRange(1, 2).getValue(); | |
Logger.log('destinationFolderId is: ' + destinationFolderId); | |
// get 'Edit' permission Flag | |
var permissionFlag = configSheet.getRange(3, 2).getValue(); | |
logEvent('Add Permissions option is: ' + permissionFlag); | |
// get 'Folder Link' column number | |
var folderLinkCol = configSheet.getRange(5, 2).getValue(); | |
Logger.log('folderLinkCol is: ' + folderLinkCol); | |
// get 'Permissions Added?' column number | |
var permAddedCol = configSheet.getRange(7, 2).getValue(); | |
Logger.log('permAddedCol is: ' + permAddedCol); | |
// get Data sheet | |
var dataSheet = ss.getSheetByName('Data'); | |
// get all data as a 2-D array | |
var data = dataSheet.getDataRange().getValues(); | |
// create a name:value pair array to send the data to the next Function | |
var spreadsheetData = {ss:ss, timeZone:timeZone, dataSheet:dataSheet, destinationFolderId:destinationFolderId, | |
permissionFlag:permissionFlag, folderLinkCol:folderLinkCol, permAddedCol:permAddedCol, data:data}; | |
// run Function to create Google Folders | |
var createFoldersFlag = createFolders(spreadsheetData); | |
// check success status | |
if (createFoldersFlag) { | |
// display Toast notification | |
ss.toast('Script complete', 'Finished'); | |
} | |
else { | |
// script completed with error | |
// display Toast notification | |
ss.toast('With errors. Please see Logs', 'Finished'); | |
} | |
// Log starting of the script | |
logEvent('Script finished'); | |
} | |
/* | |
This Function loops through each row and initiates the creation of a Google Drive Folder | |
along with a sub-folder. | |
Permissions are added if applicable. | |
*/ | |
function createFolders(spreadsheetData) { | |
// extract data from name:value pair array | |
var ss = spreadsheetData['ss']; | |
var timeZone = spreadsheetData['timeZone']; | |
var dataSheet = spreadsheetData['dataSheet']; | |
var destinationFolderId = spreadsheetData['destinationFolderId']; | |
var permissionFlag = spreadsheetData['permissionFlag']; | |
var folderLinkCol = spreadsheetData['folderLinkCol']; | |
var permAddedCol = spreadsheetData['permAddedCol']; | |
var data = spreadsheetData['data']; | |
// get last Row number | |
var lastRow = dataSheet.getLastRow(); | |
// start of loop to go through each row in turn ******************************** | |
for (var i = 1; i < lastRow; i++) { | |
// extract values from row of data so easier to work with | |
var folderNameP1 = data[i][0]; | |
Logger.log('folderNameP1 is: ' + folderNameP1); | |
var folderNameP2 = data[i][1]; | |
Logger.log('folderNameP2 is: ' + folderNameP2); | |
var subFolderName = data[i][2]; | |
Logger.log('subFolderName is: ' + subFolderName); | |
var permissionEmail = data[i][3]; | |
Logger.log('permissionEmail is: ' + permissionEmail); | |
var folderLink = data[i][4]; | |
Logger.log('folderLink is: ' + folderLink); | |
// check Folder Link column is empty before proceeding, so no existing Folder | |
if (folderLink == '') { | |
// create a name for the new Parent Folder | |
var folderName = folderNameP1 + ' - ' + folderNameP2; | |
Logger.log('Folder name is: ' + folderName); | |
// display Toast notification | |
ss.toast(folderName, 'Creating Folders'); | |
// run Function to create Parent Folder and sub-folder | |
var folderDetails = createFolder(folderName, destinationFolderId, subFolderName); | |
// check new Folders created successfully | |
if (folderDetails) { | |
// extract Url/Ids | |
var newFolderUrl = folderDetails['newFolderUrl']; | |
var newFolderId = folderDetails['newFolderId']; | |
var subFolderID = folderDetails['subFolderID']; | |
// set Folder Link cell using new Parent Folder Url | |
var newFolderLink = '=HYPERLINK("' + newFolderUrl + '","' + folderName + '")'; | |
dataSheet.getRange(i + 1, folderLinkCol).setFormula(newFolderLink); | |
// check if Permissions need adding - set in 'Config' sheet | |
if (permissionFlag == 'Yes') { | |
// run Function to add Folder permissions | |
var currentRow = i + 1; | |
var addPermissionsFlag = addPermissions(timeZone, dataSheet, permissionEmail, | |
newFolderId, subFolderID, currentRow, permAddedCol); | |
// if problem adding Permissions return for status message | |
if (addPermissionsFlag == false) { | |
// display Toast notification and return false flag | |
ss.toast('Problem adding Permissions to: ' + folderName, 'Error'); | |
return false; | |
} | |
else { | |
// no problem adding permissions | |
} | |
} | |
else { | |
// do nothing as permissions not required | |
} | |
// flush spreadsheet to update each row as completed | |
SpreadsheetApp.flush(); | |
} | |
else { | |
// write error into 'Permission Added?' cell and return false value | |
dataSheet.getRange(i + 1, folderLinkCol).setValue('Error creating folder. Please see Logs'); | |
// new Folder not created successfully | |
return false; | |
} | |
} | |
else { | |
// Folder Link column not empty so do nothing | |
} | |
}// end of loop to go through each row in turn ********************************** | |
// completed successfully | |
return true; | |
} | |
/* | |
Function to create new Google Drive Folder and return its Url/Id. | |
*/ | |
function createFolder(folderName, destinationFolderId, subFolderName) { | |
try { | |
// get destination Folder | |
var destinationFolder = DriveApp.getFolderById(destinationFolderId); | |
} | |
catch (e) { | |
logEvent('Error getting destination folder: ' + e + e.stack); | |
var destinationFolder = false; | |
} | |
// proceed if successfully got destination folder | |
if (destinationFolder) { | |
try { | |
// create new Folder in destination | |
var newFolder = destinationFolder.createFolder(folderName); | |
// get new Drive Folder Url/Id | |
var newFolderUrl = newFolder.getUrl(); | |
var newFolderId = newFolder.getId(); | |
// create sub-folder and get its Id | |
var subFolderID = DriveApp.getFolderById(newFolderId).createFolder(subFolderName).getId(); | |
// return Folder details for logging in Sheet and adding permissions | |
var folderDetails = { newFolderUrl: newFolderUrl, newFolderId: newFolderId, subFolderID: subFolderID }; | |
return folderDetails; | |
} | |
catch (e) { | |
logEvent('Error creating new Folders: ' + e + e.stack); | |
return false; | |
} | |
} | |
else { | |
// return false as unable to get destination folder | |
return false; | |
} | |
} | |
/* | |
Function to add 'Edit' permission to each Folder from the provided | |
email address(es). | |
*/ | |
function addPermissions(timeZone, dataSheet, permissionEmail, newFolderId, subFolderID, currentRow, permAddedCol) { | |
// split up email address array to be able to loop through them separately | |
var emailAddresses = permissionEmail.split(', '); | |
Logger.log('emailAddresses array is: ' + emailAddresses); | |
// get length of array for loop | |
var emailAddressesLength = emailAddresses.length; | |
try { | |
// get Google Drive Folder | |
var newFolder = DriveApp.getFolderById(newFolderId); | |
var newSubFolder = DriveApp.getFolderById(subFolderID); | |
} | |
catch (e) { | |
logEvent('Error getting destination folder: ' + e + e.stack); | |
var newFolder = false; | |
} | |
// proceed if successfully got destination folder | |
if ((newFolder) && (newSubFolder)) { | |
// loop through each email address and add as 'Editor' ******************* | |
for (var i = 0; i < emailAddressesLength; i++) { | |
var emailAddress = emailAddresses[i]; | |
Logger.log('emailAddress for adding permission is: ' + emailAddress); | |
try { | |
// add 'Edit' permission using email address | |
newFolder.addEditor(emailAddress); | |
newSubFolder.addEditor(emailAddress); | |
var addEditor = true; | |
} | |
catch (e) { | |
logEvent('Error adding Editor: ' + e + e.stack); | |
var addEditor = false; | |
} | |
if (addEditor) { | |
// write timestamp into 'Permission Added?' cell | |
var date = new Date; | |
var timeStamp = Utilities.formatDate(date, timeZone, "dd/MM/yy @ HH:mm:ss"); | |
dataSheet.getRange(currentRow, permAddedCol).setValue(timeStamp); | |
} | |
else { | |
// write error into 'Permission Added?' cell and return false value | |
dataSheet.getRange(currentRow, permAddedCol).setValue('Error adding Editor. Please see Logs'); | |
return false; | |
} | |
} | |
// loop through each email address and add as 'Editor' ******************* | |
} | |
else { | |
// write error into 'Permission Added?' cell and return false value | |
dataSheet.getRange(currentRow, permAddedCol).setValue('Error getting folder. Please see Logs'); | |
// return false as unable to get Google Drive Folder | |
return false; | |
} | |
// return true as all permissions added successfully | |
return true; | |
} | |
/* | |
Function to output messages to the 'Log' sheet. | |
Can be called anywhere else in script. | |
*/ | |
function logEvent(action) { | |
// get the user running the script | |
var theUser = Session.getActiveUser().getEmail(); | |
// get the relevant spreadsheet to output log details | |
var ss = SpreadsheetApp.getActiveSpreadsheet(); | |
var logSheet = ss.getSheetByName('Log'); | |
// create and format a timestamp | |
var dateTime = new Date(); | |
var timeZone = ss.getSpreadsheetTimeZone(); | |
var niceDateTime = Utilities.formatDate(dateTime, timeZone, "dd/MM/yy @ HH:mm:ss"); | |
// create array of data for pasting into log sheet | |
var logData = [niceDateTime, theUser, action]; | |
// append details into next row of log sheet | |
logSheet.appendRow(logData); | |
} | |
/* | |
This Function creates a menu item to run this script. | |
*/ | |
function onOpen() { | |
SpreadsheetApp.getUi() | |
.createMenu('Admin') | |
.addItem('Create folders', 'getSpreadsheetData') // label for menu item, name of function to run. | |
.addToUi(); | |
} |
Hi, this script is great but I wonder if is there a way to add multiple folders within a created subfolder? ie.
ReplyDeleteFirst folder/ (Name)
sub folder 1/ (Order number)
sub folder 2 + 3 + 4 ... (Items)
If that makes sense to you.
Thanks
Hi Darren
DeleteYes there is. This blog post may help slightly with loops and passing Parent IDs: https://www.pbainbridge.co.uk/2020/02/bulk-create-test-foldersfiles-in-google.html
Kind regards
Phil
Hi Phil – thank you so much for making this script available. I'm still learning how to use Google App scripts – is there an easy way to modify this to create a Google doc instead of a sub-folder inside of each folder?
ReplyDeleteHi
DeleteErrrm there would be several points in the script that would need tweaking to work with a Google Doc (file) instead of a sub-folder. It would be tricky to pull all of those out accurately here though.
Hopefully I can find some time in the near future to do something for this.
Kind regards
Phil
Hi Phil,
ReplyDeleteReally appreciate the Folder script and how helpful it has been for me (and everyone else)!
Would this script be able to copy a selection of existing sub-folders inside a master folder as the "subfolder" within the newly created 'Folder' that this script runs?
I have a group of sub-folders I routinely copy to new folders and this script helps me create new folders but I still need to copy over a list of sub-folders (and their content) over manually.
Any help is appreciated!
Hi Akbar
DeleteThank you for the nice feedback.
It's not really possible to 'copy' a folder in Drive/Apps Script - Google typically expects you to create a new folder as you require it. You would need to use an iterator to go through your source files/folders and create new versions/make copies of them as necessary (example of an iterator here that goes through all files in a folder - Lines 56 to 75: https://www.pbainbridge.co.uk/2019/09/bulk-rename-files-in-google-drive.html)
Towards the end of this month I'll be releasing a tool for bulk creating single folders and adding any number of files to it - so that may provide you with some further guidance.
Kind regards
Phil
Thank you for this support. I have looked through several of your posts and am still having trouble creating exactly what I need. Please see my sheet https://docs.google.com/spreadsheets/d/18yEm85y0fXLmyNxjeXJZrG7_gYy1tokqxShvCSzy6ag/edit#gid=0
ReplyDeleteI am looking to create a master folder "Master Folder (Grad Profile) that houses an individual folder for each of the students (columns A and B). Within each of the students' folders, I want to have the other sub-folders embedded (columns C-G). Would you be able to help me with this?
Hi
DeleteThat is something feasible for Apps Script to achieve. You are going into sub-sub-folders however for which I only have this blog post (https://www.pbainbridge.co.uk/2020/02/bulk-create-test-foldersfiles-in-google.html) for bulk creating test folders. It should show you the principle of creating a loop, inside a loop, inside a loop (yes a bit mind-boggling!).
If you're completely stuck and need a solution, I do Freelance work so could work together with you on this. Just use the Contact Form at the top of this page.
Kind regards
Phil
I'll see what I can accomplish. Thank you for your help.
Delete