Create Folder from new Google sheet Row - google-apps-script

Hope that somebody can help me. I create a Google script for New Folder include Hyperlink. (very new in Script)
For some reason it gives no Errors but it also creates No Folders..
The Hyperlink must be in Column R and the Name of the Folder is from the last row Column a,b together.
(is there also a possibility to Copy a existing Template Folder to a New Folder)
function createAndHyperlink() {
var ss, sh, parent, parent2, r, v, thisCell, folder
ss = SpreadsheetApp.getActive()
sh = ss.getSheetByName('MOC Permanent')
parent = DriveApp.getFileById(ss.getId()).getParents().next();
parent2 = DriveApp.getFolderById("1vxS3FebsDLqrGGQc9kG7cE3tO9zN8Qre")
r = sh.getLastRow()
v = sh.getMaxColumns()
for (var i = 0, l = v.length; i < l; i++) {
thisCell = sh.getRange(i + 3, 2)
if (v[i][0] && !thisCell.getFormula()) {
folder = parent2.createFolder(v[i][0]);
thisCell.setFormula('=HYPERLINK("' + folder.getUrl() + '"; "' + v[i][0] + '")');
}
}
}
Google Sheet :
https://docs.google.com/spreadsheets/d/12n2Cmu6OqZskD_j7YhVrU14qaQPPGnQyIoSEIw8stqE/edit?usp=sharing
Hope somebody can help me

If I understand your post correctly, you want to create Sub folders named after every row data on column A + Column B inside of your Parent Folder. Then, get each link of the Sub Folders and add each of these links on Column R as HYPERLINKS.
RECOMMENDATION
I have tweaked your current script and you may use this sample script below as reference:
UPDATED
//MAIN SCRIPT TO RUN
function createAndHyperlink() {
var ss, sh, lastRow, name;
ss = SpreadsheetApp.getActive();
sh = ss.getSheetByName('MOC Permanent');
lastRow = sh.getDataRange().getLastRow();
for(var row=2; row<=lastRow; row++){
name = sh.getRange(row,1).getValue()+sh.getRange(row,2).getValue();
if(sh.getRange(row,18).getValue().toString()==""){
sh.getRange(row,18).setFormula('=HYPERLINK('+"\""+createFolder(name).getUrl()+"\",\""+name+"\")");
Logger.log("Created a folder for "+"Name:\n"+name);
}else{
Logger.log("R"+row+" contains a hyperlink already!");
}
}
//THIS CODE BELOW ENSURES THE LAST ROW OF COLUMN R WAS ADDED WITH HYPERLINK BEFORE COPYING FUNCTION BEGINS
if(sh.getRange(lastRow,18).getValue().toString()!=""){
addTempFileCopy();
}
}
//FUNCTION TO CREATE SUB FOLDERS INSIDE THE PARENT FOLDER
function createFolder(folderName){
var parent, folders, firstLevelFolder, newfolder;
parent = DriveApp.getFolderById("PARENT_FOLDER_ID").getName();
folders = DriveApp.getFoldersByName(parent);
firstLevelFolder = (folders.hasNext()) ? folders.next() : DriveApp.createFolder(parent);
//CREATE UNIQUE SUBFOLDERS INSIDE OF THE PARENT FOLDER
newfolder = firstLevelFolder.createFolder(folderName);
return newfolder; //RETURNS THE LINK OF THE CREATED SUBFOLDER
}
//FUNCTION TO ADD THE TEMPLATE FILE INTO EACH CREATED SUB FOLDERS
function addTempFileCopy(){
var parent, subFolder, ss;
ss = SpreadsheetApp.getActive();
parent = DriveApp.getFolderById("PARENT_FOLDER_ID").getFolders();
while(parent.hasNext()) {
subFolder = parent.next();
var destFolder = DriveApp.getFolderById(subFolder.getId());
DriveApp.getFileById(ss.getId()).makeCopy(subFolder.getName()+" - Template file copy", destFolder);
Logger.log("Template file name: "+ss.getName()+"\nAdded to folder: "+subFolder.getName());
}
}
SAMPLE SHEET
RESULT
After running the script, HYPERLINKS were added on the on COLUMN R:
Here are the created Sub folders on Google Drive inside of the Parent folder:
Execution log result:

Related

Check if folder exists in EITHER parent folder, else create

I have two parent folders that I want to check if Folder(folderName) exists in. folderName is defined by the range S2:2 in my spreadsheet
If Folder(folderName) does not exist in EITHER parent folder, then I want that folder to be created in Parent Folder 1.
So far my script is managing to check Parent Folder 1 and create in Parent Folder 1, but is not checking Parent Folder 2.
This is the script I have so far:
function myfunction() {
var parent = DriveApp.getFolderById("parent Folder 1")
SpreadsheetApp.getActive().getSheetByName('Letter History').getRange('S2:S').getValues()
.forEach(function (r) {
if(r[0]) checkIfFolderExistElsesCreate(parent, r[0]);
})
}
function checkIfFolderExistsElseCreate(parent, folderName) {
var folder;
try {
folder = parent.getFoldersByName(folderName).next();
} catch (e) {
folder = parent.createFolder(folderName);
}
function myFunction() {
var parentFolder1 = DriveApp.getFolderById('<ParentFolder1 ID>').getFolders(); //Get ID for Folder 1
var parentFolder2 = DriveApp.getFolderById('<ParentFolder2 ID>').getFolders(); //Get ID for Folder 2
var sheet = SpreadsheetApp.getActive().getSheetByName('Letter History');
//Iterating to read all the subfolders in ParentFolder 1 and 2
var childNames = [];
while (parentFolder1.hasNext()) {
var child = parentFolder1.next();
childNames.push([child.getName()]);
}
while (parentFolder2.hasNext()) {
var child = parentFolder2.next();
childNames.push([child.getName()]);
}
//Checking if the subfolder/s is existing or not, then creating in folder 1 if not yet existing
var data = sheet.getRange(2, 19, sheet.getLastRow() - 1, 1).getValues(); //S = 19, Change 19 according to column.
for (var i = 0; i < data.length; i++) {
if (childNames.flat().includes(data[i][0])) {
console.log(data[i][0] + "- already exist")
} else {
DriveApp.getFolderById('<ParentFolder1 ID>').createFolder(data[i][0])
console.log(data[i][0] + "- has been created")
}
};
}
The above code will create subfolder/s in Folder 1 based on range S2:S column in spreadsheet, if it is checked that the subfolder name does not yet exist either in Parent Folder 1 or 2.
Please take note to change the following:
ParentFolder 1 ID
ParentFolder 2 ID
Reference: How to create a folder if it doesn't exist?
I believe your goal is as follows.
You want to expand your showing script for using 2 parent folders.
In this case, how about the following sample script?
Sample script:
Please set your parent folder IDs to parentFolderIDs and save the script.
function myfunction() {
// Please set your parent folder IDs you want to use.
const parentFolderIDs = ["###parent folder ID1###", "###parent folder ID2###"];
// 1. Retrieve subfolders from folders of parentFolderIDs.
const parentFolders = parentFolderIDs.map(id => DriveApp.getFolderById(id));
const subFolders = parentFolders.map(folder => {
const temp = [];
const folders = folder.getFolders();
while (folders.hasNext()) {
temp.push(folders.next().getName());
}
return { parent: folder, subFolderNames: temp };
});
// 2. Create new folders when the folder names are not existing.
const sheet = SpreadsheetApp.getActive().getSheetByName('Letter History');
const values = sheet.getRange('S2:S' + sheet.getLastRow()).getDisplayValues();
values.forEach(([s]) => {
if (s) {
subFolders.forEach(({ parent, subFolderNames }) => {
if (!subFolderNames.includes(s)) {
parent.createFolder(s);
}
});
}
});
}
When this script is run, the subfolders in parentFolderIDs are retrieved. And, using the retrieved subfolders, the new subfolders are created in the parent folders of parentFolderIDs.
References:
map()
forEach()

Google Script Question: Is there a way to create copies of files into multiple folders at once?

I have a spreadsheet from which I've written code to populate with the names of folders (column 1) and their IDs (column 2).
I would like to populate each of the folders listed in that spreadsheet with a copy of each of the documents contained a separate folder (a Shared Drive folder, if that matters). When I execute the code below, a copy of each document is created in the source folder (the Shared Drive folder) instead of in the destination folder (aka the folders whose IDs are captured in the spreadsheet). If it matters, each copy is labelled with a folderID from the spreadsheet. Can someone please tell me how I can get this code to create the copies inside the appropriate destination folders instead of in the source folder?
function CopiestoFolder() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getDataRange() //Get all non-blank cells
.getValues() //Get array of values
.splice(1); //Remove header line
//Define column numbers for data. Array starts at 0.
var NAME = 0;
var FOLDERID = 1;
//For each folder ID listed in spreadsheet, create a copy of
//each item in the Resume Resources folder.
for (var i = 0; i < data.length; i++) {
var name = data[i][NAME];
var folderId = data[i][FOLDERID];
var srcFolder = DriveApp.getFolderById("folder ID");
var dstFolder = folderId;
var files = srcFolder.getFiles();
while (files.hasNext()) {
var file = files.next();
var f = file.makeCopy(dstFolder);
if (file.getMimeType() == MimeType.GOOGLE_APPS_SCRIPT) {
dstFolder.addFile(file);
f.getParents().next().removeFile(file);
}
}
}
}
I had this problem with Script Files. Here's how I fixed. Or I should say here's how Tanaike fixed it. You will need to enable Drive API.
var res=file.makeCopy(copyName,subFldr);
if (file.getMimeType() == MimeType.GOOGLE_APPS_SCRIPT) {
Drive.Files.update({"parents": [{"id": subFldr.getId()}]}, res.getId(), null, {"supportsTeamDrives":true}); // Added
}
The file.makeCopy() method has 3 overloads:
//Accepts no parameters
file.makeCopy();
//Accepts a name parameter as a string
file.makeCopy(name);
//Accepts a destination parameter as an instance of a Folder class
file.makeCopy(destination);
//Accepts 2 parameters, the first of which is name (String) and the second one is destination (Folder).
file.makeCopy(name, destination);
You are trying to pass folder id instead of the actual folder, which gets interpreted as a folder name (not destination). Also, the following code means that your 'dstFolder' parameter is a string but you try to call the 'addFile()' method on it:
var folderId = data[i][FOLDERID];
var dstFolder = folderId;
dstFolder.addFile(file);
If you want to copy a file to another folder via makeCopy, you should pass a Folder as a parameter, not a folder id (a string). If you provide a string (your id) as a parameter, the script will interpret this id as the name you want the copied file to have. So you should first get the Folder out of its id, via getFolderById(id). So you should change this line:
var dstFolder = folderId;
To this one:
var dstFolder = DriveApp.getFolderById(folderId);
You are making a copy of the file before checking if the file is a Google Apps Script project. I assume you just want GAS projects to be copied, so this should be included inside the if block. Also, inside the if block you are using addFile which can also be used to copy a file to another folder (it adds the file to the desired folder). So you don't need to use both functions, they are doing basically the same (copying your file to the desired folder).
You are using removeFile, which is not necessary if you want to keep the original files in the original folders.
So the while block could be something like:
while (files.hasNext()) {
var file = files.next();
if (file.getMimeType() == MimeType.GOOGLE_APPS_SCRIPT) {
dstFolder.addFile(file);
}
}
Finally, your full code could be like:
function CopiestoFolder() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getDataRange() //Get all non-blank cells
.getValues() //Get array of values
.splice(1); //Remove header line
//Define column numbers for data. Array starts at 0.
var NAME = 0;
var FOLDERID = 1;
//For each folder ID listed in spreadsheet, create a copy of
//each item in the Resume Resources folder.
for (var i=0; i<data.length; i++) {
var name = data[i][NAME];
var folderId = data[i][FOLDERID];
var srcFolder = DriveApp.getFolderById("folder ID");
var dstFolder = DriveApp.getFolderById(folderId);
var files = srcFolder.getFiles();
while (files.hasNext()) {
var file = files.next();
if (file.getMimeType() == MimeType.GOOGLE_APPS_SCRIPT) {
dstFolder.addFile(file);
}
}
}
}
I hope this is of any help.

How can I access last created sub folder and its files in google drive using google-apps-script

I need to access the last created subfolder from a parent folder and subfolder's files but i'm failing to do so. Any help in this regard would be highly appreciated.
I'm trying to get files of the last created folder but it gives me an error.
function myFunction() {
// set the folder to pull folder names from
var parentid = "19mrz1uwYVCnmW1XZJYq3";
var parent = DriveApp.getFolderById(parentid);
var parentfolder= parent.getfolders();
var folders = parentfolder.getLastupdated();
var dd = folders.getfiles();
}
I need to excess the last created subfolder and work on it's content to copy somewhere else.
You can find the newest folder with the JS function reduce() and the Apps Script method getDateCreated().
Sample:
function myFunction() {
var parentid = "19mrz1uwYVCnmW1XZJYq3";
var parent = DriveApp.getFolderById(parentid);
var parentfolder= parent.getFolders();
var array=[];
var arrayFolders=[];
while (parentfolder.hasNext()) {
var folders = parentfolder.next();
array.push(folders.getDateCreated());
arrayFolders.push(folders.getId());
}
var date=array.reduce(function (a, b) {
return a > b ? a : b;
});
var index=array.indexOf(date);
var newestFolder=DriveApp.getFolderById(arrayFolders[index]);
var myFiles=newestFolder.getFiles();
}

Google Apps - How to get all files name from current directory?

How I can get all files name from current directory?
I have a code
function showAllFollderFronRoot() {
// get all files from the ROOT folder
var files = parentFolder;
while (files.hasNext()) {
var file = files.next();
// Logger.log(file.getName());
DocumentApp.getUi().alert(file.getName());
}
}
But it work only with ROOT dir.
How I can get all file names in array in current dir?
UPDATE:
I have a file structure: MT/MT.100-107/MT.100-1007.1001.doc
I need make code, if somebody open New Template from Docs - script need automatically safe this file with true structure - with next filename + 1 (example MT.100-1007.1002.doc, next new file from Template - MT.100-1007.1003.doc ...)
Script need to find all filenames => show last bigger count (1002.doc) => count + 1 => save this file with new filename MT.100-1007.1003.doc
My code work, but it make tmp file in Root dir & not work perfect, because it not calculate last bigger count in current dir and if I delete file, example MT.100-1007.1003.doc in dir MT, and make new file in dir UA - count be MT.100-1007.1004.doc no matter what the names of the files are in the folder UA.
These script with mistakes, how I can fix it?
/**
* #OnlyCurrentDoc
*/
function saveFilename() {
// Get current file name
const ui = DocumentApp.getUi(),
doc = DocumentApp.getActiveDocument(), //Added
thisFileId = doc.getId(),
thisFileName = doc.getName();
const thisFile = DriveApp.getFileById(thisFileId);//Modified from getFolderById
const parentFolder = thisFile.getParents();
const currentFolder = parentFolder.next();//Modified from currentFolderName
const currentFolderName = currentFolder.getName();//Added
//ui.alert(currentFolderName);
/*Store a init file in root to getLatestFileNumber*/
var initIter = DriveApp.getFilesByName(currentFolderName + 'init00'),
initBool = initIter.hasNext(),
init;
if (!initBool) {
init = DriveApp.createFile(currentFolderName + 'init000', '0');
} else {
init = initIter.next();
}
/*Get current Number and format it to 4 digits*/
var currentNum = init.getBlob().getDataAsString() * 1 + 1,
formatNum = ('0000' + currentNum).substr(-3);
/*If filename already contains folderName, do nothing*/
if (!(thisFileName.search(currentFolderName) + 1)) {
doc.setName(currentFolderName +'.' + formatNum).saveAndClose();
init.setContent(currentNum);
}
// delete TMP file from ROOT dir
DriveApp.getFileById(init.getId()).setTrashed(true)
}
You want to retrieve filenames of all files in the parent folder of the active document.
If my understanding is correct, how about this answer?
Flow:
The flow of this script is as follows.
Retrieve file ID of the active document.
Retrieve parent folder ID of the active document.
Retrieve files in the parent folder ID.
Retrieve filenames of files.
Modified script:
function showAllFollderFronRoot() {
var fileId = DocumentApp.getActiveDocument().getId();
var parentFolderId = DriveApp.getFileById(fileId).getParents().next().getId();
var files = DriveApp.getFolderById(parentFolderId).getFiles();
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName())
}
}
Note:
This sample script supposes as follows.
The parent of the active document is only one.
All files in the parent folder of the active document are retrieved. But the folders are not retrieved.
References:
getId()
getParents()
getFolderById(id)
getFiles()
If I misunderstand your question, please tell me. I would like to modify it.
I fix this problem, but idk how to parse last 4 digits in filename and find MAX from it. Do you have any idea? method slice(4) not working in apps script :(
function currFiles() {
const ui = DocumentApp.getUi(),
doc = DocumentApp.getActiveDocument(),
thisFileId = doc.getId(),
thisFileName = doc.getName();
const thisFile = DriveApp.getFileById(thisFileId);
const parentFolder = thisFile.getParents();
const currentFolder = parentFolder.next();
const currentFolderName = currentFolder.getName();
const currentFolderId = currentFolder.getId();
// get all files in currentFolder
var folderId = currentFolderId;
// Log the name of every file in the folder.
var files = DriveApp.getFolderById(folderId).getFiles();
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
}
}

How to insert in a cell the name and link of a folder that has just been created in Google Drive?

I'd like to create some folders in Google Drive through a script in Google Sheets and then to get the URLs of the new folders to put them in a cell.
I successfully created the folders based on the column "Employee ID" and replaced the values of the column "Employee ID" with the folder hyperlinks.
So I get the 3 folders created in Google Drive: 1,2 and 3, respectively. The problem is that my code repeats the same name and URL in every row in the Google Sheets setting the name and URL of the last folder that was created (the folder 3 in this case).
I would appreciate it if you could give me some help with this. This is my code:
function onEdit(e) {
if ([1, 2,].indexOf(e.range.columnStart) != 1) return;
createEmployeeFolder();
}
function createEmployeeFolder() {
var parent = DriveApp.getFolderById("1H0i69rE9WO0IAoxhnrFY2YKT_tD50fuX")
SpreadsheetApp.getActive().getSheetByName('Database').getRange('B3:B').getValues()
.forEach(function (r) {
if(r[0]) checkIfFolderExistElseCreate(parent, r[0]);
})
}
function checkIfFolderExistElseCreate(parent, folderName) {
var folder;
var idfolder;
var link;
try {
folder = parent.getFoldersByName(folderName).next();
} catch (e) {
folder = parent.createFolder(folderName);
idfolder = folder.getId();
link = folder.getUrl();
formula = '=hyperlink("' + link + '",' + folder + ')';
SpreadsheetApp.getActive().getSheetByName('Database').getRange('B3:B').setFormula(formula);
}
}
Ok I changed my code for this. I can create the folders but the problem is with the SetFormula I can't make it work in order to read every row to replace the ID with the URL. It just take the last ID and then it repeats the same ID in all the rows from the range. Please some help! :P
function createEmployeeFolder() {
var parent = DriveApp.getFolderById("1H0i69rE9WO0IAoxhnrFY2YKT_tD50fuX")
SpreadsheetApp.getActive().getSheetByName('Database').getRange('B3:B').getValues()
.forEach(function (r) {
if(r[0]) createFolder(r[0]);
})
}
function createFolder(folderName) {
var parent = DriveApp.getFolderById("1H0i69rE9WO0IAoxhnrFY2YKT_tD50fuX");
var projectFolder;
if (parent.getFoldersByName(folderName).hasNext()) {
// folder already exists
Folder = parent.getFoldersByName(folderName).next();
} else {
Folder = parent.createFolder(folderName);
}
var id = Folder.getId();
var link = Folder.getUrl();
var formula = '=hyperlink("' + link + '",' + Folder + ')';
SpreadsheetApp.getActive().getSheetByName('Database').getRange('B3:B').setFormula(formula);
return formula;
}
I have a function that does this for me. It takes a userName and returns a formula for a link to the folder that either existed or was created. This link can be put into a cell using setFormula():
function createUserFolder(userName) {
var parent = DriveApp.getFolderById("1H0i69rE9WO0IAoxhnrFY2YKT_tD50fuX");
if (parent.getFoldersByName(userName).hasNext()) {
// folder already exists
userFolder = parent.getFoldersByName(userName).next();
} else {
userFolder = parent.createFolder(userName);
}
var id = userFolder.getId();
var formula = '=HYPERLINK("https://drive.google.com/open?id=' + id + '","Files")'
return formula;
}
Please note however that you should rethink your code quite dramatically. onEdit is called for every single change in the spreadsheet which is very wasteful. Iterating through every single cell in column B is very wasteful. Using the catch clause in a try to do your critical code is a bad idea.
I would add a dialog or other ui to the sheet for triggering the creation of the folder rather than monitoring the sheet continually.
Solution:
The following script creates a folder in drive and a link with the name of the folder within a cell automatically.
function createAndHyperlink() {
var ss, sh, parent, parent2, r, v, thisCell, folder
ss = SpreadsheetApp.getActive()
sh = ss.getSheetByName('INSERTTHENAMEOFYOURSHEETHERE')
parent = DriveApp.getFileById(ss.getId()).getParents().next();
parent2 = DriveApp.getFolderById("INSERT-YOURGOOGLEDRIVEFOLDERIDEHERE")
r = sh.getRange('B3:B')
v = r.getValues()
for (var i = 0, l = v.length; i < l; i++) {
thisCell = sh.getRange(i + 3, 2)
if (v[i][0] && !thisCell.getFormula()) {
folder = parent2.createFolder(v[i][0]);
thisCell.setFormula('=HYPERLINK("' + folder.getUrl() + '"; "' + v[i][0] + '")');
}
}
}
Your issue stems from incomplete refactoring - you split the task of getting the folder id into a separate method, but also split the task of setting the hyperlink into that Range-unaware code.
The solution to repeating the last value across all other rows is to fix your refactoring - setting the formulas should be done where the range to write to is known.
function createEmployeeFolder() {
const parent = DriveApp.getFolderById("some id");
const sheet = SpreadsheetApp.getActive().getSheetByName('Database');
const range = sheet.getRange(3, 2, sheet.getLastRow() - 2);
range.getValues().forEach(function (row, index) {
// Consider checking if this r & c has a formula in the equal size array from getFormulas()
if(row[0]) {
var newLink = getLinkForFolderName_(parent, row[0]);
// Use the current array index to write this formula in only the correct cell.
range.offset(index, 0, 1).setFormula(
"=hyperlink(\"" + newLink + "\", \"" + row[0] + "\")";
);
}
});
}
function getLinkForFolderName_(root, name) {
var folder;
const search = root.getFoldersByName(name);
if (search.hasNext()) {
folder = search.next();
if (search.hasNext())
console.warn("Multiple folders named '" + name + "' in root folder '" + root.getName() + "'");
}
else
folder = root.createFolder(name);
return folder.getUrl();
}
You should do away with the onEdit simple trigger binding since simple triggers cannot create folders (you need authorization for that) - just change the name and install the on edit trigger for the new name. Another option is to use a menu option that calls this function. However, one (possible) benefit of using an installed trigger is that all folders will be owned by the same account.