I have the following code in a Spreadsheet app that:
Creates a folder in a given location;
Finds and copies a set of template folders and files from a master directory;
Moves them into the folder created in step 1.
However, periodically, the template folders are not moved during step 3 and remain under the Root. It seems to consistently happen with one specific set of templates that contains 21 folders and 38 files with a total size of 2.64 MB.
There are no errors that are highlighted in the App Script editor. The script message ends as expected.
Can anyone suggest why this may be happening and help with the code to prevent this from occurring.
Update: When this error occurs, I am left with a copy of the template folder in the Root of MyDrive. If I then run the 'moveFolder()' function on its own the problematic template folder move works 100%.
My Code:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Admin')
.addItem('Create Project', 'createProjectFolder')
.addItem('Get Template Folder', 'start')
.addItem('Move Template Folder', 'moveFolder')
.addToUi();
}
//******************************************************************************** */
//Create new Project Folder
//******************************************************************************** */
function createProjectFolder(FolderName, TargetFolder)
{
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Config');
var newFolderName = sh.getRange('NewProjectName').getValue();
//Change 'parentFolder' ID to the Verification Projects
var parentfolder = DriveApp.getFolderById('ID'); //Folder ID of Verification Projects folders
var newFolder = DriveApp.createFolder(newFolderName);
var currentFolders = newFolder.getParents();
while (currentFolders.hasNext())
var currentFolder = currentFolders.next();
currentFolder.removeFolder(newFolder);
parentfolder.addFolder(newFolder);
var newFolderID = newFolder.getId();
Logger.log(newFolderID)
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var configSheet = spreadSheet.getSheetByName('Config');
var range = configSheet.getRange('NewProjectNameID').setValue(newFolderID);
start();
return newFolderID;
}
//**************************************************************** */
//Copy master folder structure
//**************************************************************** */
function start() {
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var configSheet = spreadSheet.getSheetByName('Config');
var sourceFolder = configSheet.getRange('SourceFolder').getValue();
var targetFolder = configSheet.getRange('ProjectFolderLibraryName').getValue();
Logger.log(sourceFolder);
Logger.log(targetFolder);
var source = DriveApp.getFoldersByName(sourceFolder);
var target = DriveApp.createFolder(targetFolder);
if (source.hasNext()) {
copyFolder(source.next(), target);
}
}
function copyFolder(source, target) {
var folders = source.getFolders();
var files = source.getFiles();
while (files.hasNext()) {
var file = files.next();
file.makeCopy(file.getName(), target);
}
while (folders.hasNext()) {
var subFolder = folders.next();
var folderName = subFolder.getName();
var targetFolder = target.createFolder(folderName);
copyFolder(subFolder, targetFolder);
}
moveFolder();
}
function moveFolder(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('Config');
var folderName = sh.getRange('ProjectFolderLibraryName').getValue();
Logger.log(folderName);
var folderNameID = sh.getRange('NewProjectNameID').getValue();
Logger.log(folderNameID);
var folder = DriveApp.getFoldersByName(folderName).next();
var destination = DriveApp.getFolderById(folderNameID);
destination.addFolder(folder);
folder.getParents().next().removeFolder(folder);
}
This has been resolved. I was calling the next function from within the current function. I suspect that the call to execute the next function was placed too early and conflicts then arose.
Solution: I created a separate function that contained the functions in order. This allowed each function to complete before the next was executed.
EG:
function allFunctions(){
function1();
function2();
function3();
}
Related
I currently have a script that I'm using, which I based on a script that I found, to copy a Google sheet to all the other Spreadsheets that are in the same Google Drive folder. I'd like to modify this to copy the sheet to all the other Spreadsheets that are in a different folder using the folder ID. I've tried modifying the var folderFiles to use the DriveApp.getFolderByID to direct it to a specific folder but just keep getting errors. I'm more of a novice so any help or guidance would be greatly appreciated.
function copySheetVA() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getActiveSheet();
var sourceFile = DriveApp.getFileById(source.getId());
var sourceFolder = sourceFile.getParents().next();
var folderFiles = DriveApp.getFolderById('1zZDvtFzIvmD-7Z5f5Sbi4G3-XXXXX');
var thisFile;
while (folderFiles.hasNext()) {
thisFile = folderFiles.next();
if (thisFile.getName() !== sourceFile.getName()){
var currentSS = SpreadsheetApp.openById(thisFile.getId());
var actualSheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
sheet.copyTo(currentSS);
currentSS.getSheets()[currentSS.getSheets().length-1].setName(actualSheetName);
}
};
}
I updated your code and tested it on my end.
The fix is to call getFiles() after get the folder,
var folderFiles = DriveApp.getFolderById('YOUR_FOLDER_ID').getFiles();
function copySheetVA() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getActiveSheet();
var sourceFile = DriveApp.getFileById(source.getId());
var folderFiles = DriveApp.getFolderById('YOUR_FOLDER_ID').getFiles();
while (folderFiles.hasNext()) {
var thisFile = folderFiles.next();
if (thisFile.getName() !== sourceFile.getName()){
var currentSS = SpreadsheetApp.openById(thisFile.getId());
var actualSheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
sheet.copyTo(currentSS);
currentSS.getSheets()[currentSS.getSheets().length-1].setName(actualSheetName);
}
};
}
I am trying to copy a given folder and its contents (sub folders and files) to a new folder using a simple Ui Prompt for the target folder name.
This is my updated script after suggestions from Meera:
function start() {
var sourceFolder = 'SourceFolderName'; // Folder exists in Drive
var source = DriveApp.getFoldersByName(sourceFolder);
var ui = SpreadsheetApp.getUi();
var folderPrompt = ui.prompt('Enter the Target Folder Name');
Logger.log(folderPrompt.getResponseText());
if (folderPrompt.getSelectedButton() == ui.Button.OK){
var target = folderPrompt.getResponseText();
if (source.hasNext()) {
copyFolder(source.next(), target);
}
Logger.log(target);
function copyFolder(source, target) {
var folders = source.getFolders();
var files = source.getFiles();
while (files.hasNext()) {
var file = files.next();
file.makeCopy(file.getName(), target);
var target_folder = DriveApp.getFoldersByName(target); // Added as per Meera
var target = target_folder.next(); // Added as per Meera
}
while (folders.hasNext()) {
var subFolder = folders.next();
var folderName = subFolder.getName();
var targetFolder = target.createFolder(folderName);
copyFolder(subFolder, targetFolder);
}
}
}
}
The prompt box still displays but after entering the folder name and selecting OK nothing happens. Still no new target folder is created.
You need to make sure that you have a folder in your google Drive with the name "SourceFolderName" as you entered in line 2 of code. Else change the value to any existing folder name.
Also in the copyFolder function, the file.makeCopy(file.getName(), target); will not work as target is just the name(string) of the target folder. You have to add below two lines of code to get the folder var target_folder=DriveApp.getFoldersByName(target);var target=target_folder.next(); [refer here ]and the rest will work.
I have found a solution for target.createFolder is not a function.
When passing the target it is a string. Using the method getFoldersByName for the target folder as well you can get a folder instead of a string.
I have modified the script like:
function start() {
var sourceFolder = 'sourceFolder';
var targetFolder;
var ui = SpreadsheetApp.getUi();
var folderPrompt = ui.prompt('Enter the Target Folder Name');
//Logger.log(folderPrompt.getResponseText());
if (folderPrompt.getSelectedButton() == ui.Button.OK) {
targetFolder = folderPrompt.getResponseText();
}
var source = DriveApp.getFoldersByName(sourceFolder);
var folders = DriveApp.getFoldersByName(targetFolder);
while (folders.hasNext()) {
var folder = folders.next();
}
if (source.hasNext()) {
copyFolder(source.next(), folder);
}
}
function copyFolder(source, target) {
var folders = source.getFolders();
var files = source.getFiles();
while (files.hasNext()) {
var file = files.next();
file.makeCopy(file.getName(), target);
}
while (folders.hasNext()) {
var subFolder = folders.next();
var folderName = subFolder.getName();
var targetFolder = target.createFolder(folderName);
copyFolder(subFolder, targetFolder);
}
}
due to some File migration from a Fileserver to Google Drive for a bunch of users in a company, it is necessary that I change the ownership of a Folder and all its containing subfolders and Files.
First I copy the whole folder to my drive(get the ownership this way), then I start my script to transfer the ownership to the new owner.
I wrote a small Script that is working fine for some smaller Folders (<1GB approx.) but almost always gives me an Error when transferring ownership of bigger ones:
Action not allowed (Line 85, File"Code")
Line 85 is containing the following code:
file.setOwner(newOwner);
I have to run that script a few times, sooner or later it finishes successfully.
Have no clue why the script gets that error.
Any Ideas?
Many thanks!
The script:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Transfer')
.addItem('Transfer Folder', 'Transferfolder')
.addSeparator()
.addItem('Disable Sharing Settings for Editors', 'Ownersettings')
.addToUi();
}
function Transferfolder()
{
var me=Session.getActiveUser().getEmail();
var ss = SpreadsheetApp.getActive();
var data = ss.getDataRange().getValues();
var idname=data[2][1];
var newOwner=data[3][1];
var fol = DriveApp.getFolderById(idname);
subfolderTransfer(fol,me,newOwner);
}
function Ownersettings()
{
var me=Session.getActiveUser().getEmail();
var ss = SpreadsheetApp.getActive();
var data = ss.getDataRange().getValues();
var idname=data[2][1];
var fol = DriveApp.getFolderById(idname);
disablesharebyeditors(fol,me);
}
function disablesharebyeditors(fol,me)
{
var files = fol.getFiles();
var folders=fol.getFolders();
Logger.log(fol.getOwner().getEmail());
if(fol.getOwner().getEmail()==me){
fol.setShareableByEditors(false);
Logger.log(fol);
}
while (files.hasNext())
{
var file = files.next();
if(file.getOwner().getEmail()==me){
file.setShareableByEditors(false);
}
}
while (folders.hasNext())
{
var subfolder = folders.next();
disablesharebyeditors(subfolder,me);
}
}
function subfolderTransfer(fol,me,newOwner)
{
Logger.log("subfolderTransfer");
var files = fol.searchFiles('"me" in owners');
var folders=fol.searchFolders('"me" in owners')
Logger.log(fol.getName());
if(fol.getOwner().getEmail()==me){
fol.setOwner(newOwner);
}
//file.removeEditor(me);
while (files.hasNext())
{
var file = files.next();
Logger.log(file.getName());
if(file.getOwner().getEmail()==me){
file.setOwner(newOwner);
}
}
Logger.log("folders");
while (folders.hasNext())
{Logger.log(fol.getName());
var subfolder = folders.next();
subfolderTransfer(subfolder,me,newOwner);
}
}
function transferfiles(files,me,newOwner)
{
while (files.hasNext())
{
var file = files.next();
if(file.getOwner().getEmail()==me){
file.setOwner(newOwner);
}
//file.removeEditor(me);
}
}
I am attempting to copy an individual spreadsheet to all spreadsheet files within a folder. I could not figure out how to do it, so I am using a previous code I found that lists all of the files, but it ends up listing all of the files in my drive, not just in that folder.
Could I get assistance either in making a script to copy it to all files in a specific folder, or change it so that the below code shows only that of the folder it is in? From what I have seen/changed DriveApp.getFiles() should only be listing those files in the folder?
function List()
{
var app = UiApp.createApplication();
app.setTitle("Copy Sheet in Multiple Spreadsheets");
var form = app.createFormPanel();
var flow = app.createFlowPanel();
var label = app.createLabel("Select Spreadsheet where you want to copy the current sheet:").setId('selectLabel');
flow.add(label);
var allfiles = DriveApp.getFiles();
var verticalPanel = app.createVerticalPanel().setId('verticalPanel');
var i = 0;
while (allfiles.hasNext())
{
var file = allfiles.next();
var temp = app.createCheckBox(file.getName()).setName('cb'+i).setId('cb'+i);
var tempvalue = app.createHidden('cbvalue'+i, file.getId());
verticalPanel.add(temp);
verticalPanel.add(tempvalue);
i++;
}
var scrollPanel = app.createScrollPanel().setId('scrollPanel');
scrollPanel.add(verticalPanel);
scrollPanel.setSize("400", "250")
flow.add(scrollPanel);
var buttonsubmit = app.createSubmitButton("Copy");
flow.add(buttonsubmit);
form.add(flow);
app.add(form);
SpreadsheetApp.getActiveSpreadsheet().show(app);
return app;
}
function doPost(eventInfo) {
var app = UiApp.getActiveApplication();
var allfiles = DriveApp.getFiles();
var tempSsId = "";
var i = 0;
while (allfiles.hasNext())
{
var temp = eventInfo.parameter['cb'+i];
if(temp == 'on')
{
tempSsId = eventInfo.parameter['cbvalue'+i];
var activeSheet = SpreadsheetApp.getActiveSheet().copyTo(SpreadsheetApp.openById(tempSsId));
activeSheet.setName(SpreadsheetApp.getActiveSheet().getSheetName());
}
i++;
}
var label = app.createLabel('statusLabel');
label.setText("Copied Active sheet in all selected Spreadsheets...");
label.setVisible(true);
app.add(label);
return app;
}
DriveApp.getFiles(); will get every file in your Drive.
DriveApp.getFolderById('folder id').getFiles(); If you want to get files in a specific folder (this will get the files in that folder but not in subfolders).
This script has nothing to do with the question you asked and I think you may have worded your question incorrectly.
Do you mean you are attempting to copy an individual sheet from a spreadsheet to all of the other spreadsheets in a particular folder?
EDIT
function copyTo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = ''; // ENTER THE NAME OF THE SHEET YOU WANT TO COPY
var targetFolder = DriveApp.getFolderById(''); //ENTER THE ID OF THE TARGET FOLDER HERE
var sheet = ss.getSheetByName(sheetName);
var getFiles = targetFolder.getFiles();
while (getFiles.hasNext()) {
var file = getFiles.next();
if (file.getMimeType() == 'application/vnd.google-apps.spreadsheet') {
var targetSheet = SpreadsheetApp.openById(file.getId());
sheet.copyTo(targetSheet).setName(sheetName);
}
}
}
I have a sheet which I need to copy to hundreds of spreadsheets in a given folder in Google Drive. I am just beginning with script and I do not know how to proceed because the script below just gives me an error. Thanks.
function myFunction() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[0];
var folder = DriveApp.getFoldersByName('TEST FOR SCRIPT');
var contents = folder.getFiles();
for (var i = 0; i < contents.length; i++) {
file = contents[i];
}
sheet.copyTo(contents).setName('ANSWERS');
}
I was given this answer by someone within a community in Google+ and it works:
function copyToSheets() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[1];
var folders = DriveApp.getFoldersByName('ID');
var firstFolder = folders.next();
var folderFiles = firstFolder.getFiles();
var thisFile;
while (folderFiles.hasNext()) {
thisFile = folderFiles.next();
var currentSS = SpreadsheetApp.openById(thisFile.getId());
sheet.copyTo(currentSS);
currentSS.getSheets()[currentSS.getSheets().length-1].setName('NAME');
}
}
This line of code:
var folder = DriveApp.getFoldersByName('TEST FOR SCRIPT');
returns a FolderIterator. Even if you only have one folder by that name, the getFoldersByName() method returns an object, that you can't use the getFiles() method on directly. The getFiles() method works on the Files Class. It is not available to the Folder Iterator. After you get the Folder Iterator, you must use the next() method to get the first (and probably only) folder in the object.
function getAllFilesInFolder() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[0];
var folders = DriveApp.getFoldersByName('Folder Name Here');
var firstFolder = folders.next();
var folderFiles = firstFolder.getFiles();
var thisFile;
while (folderFiles.hasNext()) {
thisFile = folderFiles.next();
Logger.log(thisFile.getName());
};
};
And also use hasNext() to loop through the files. There doesn't seem to be an length property of the Files object.