Batch File Running but not Following All Steps/Apps Script also hit and miss [closed] - csv

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 months ago.
Improve this question
Task: Move and rename .csv reports from a shared server folder to my Google Drive. At this point my apps script will take over and import into a specified Sheet. The apps scripts are embedded into each sheet (7 sheets total) but they are all the exact same code (changed for the specific files and sheets).
Issue 1: The batch script works every time flawlessly when run manually, but when scheduled, sometimes it will not rename my files (but will still move them).
Issue 2: The apps script is hit and miss, sometimes it runs perfectly and sometimes it fails with an error
"TypeError: Cannot read property 'clearContents' of null".
Thus the Sheet is not updated and I have csv files sitting in my drive doing nothing.
Batch Script
#echo off
ren "\\Server\Folder\subfolder\DataDaily-Emb Smalls-*.csv" smalls.csv
ren "\\Server\Folder\subfolder\DataDaily-HP & Laser-*.csv" hp.csv
ren "\\Server\Folder\subfolder\DataDaily-Emb Hats-*.csv" hats.csv
ren "\\Server\Folder\subfolder\DataDaily-Embroidery-*.csv" emb.csv
ren "\\Server\Folder\subfolder\DataDaily-Screen Print-*.csv" sp.csv
ren "\\Server\Folder\subfolder\DataDaily-Database-*.csv" database.csv
robocopy \\Server\Folder\subfolder "G:\My Drive\Dashboard" /MOV /XF *.bat
Apps Script Example hobbled together from different posts on this forum, it works on every other sheet except for this one
function RecImport() {
const csvFolderName = 'FolderName';
var file = DriveApp.getFilesByName("rec.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("rec");
sheet.clearContents();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
DriveApp.getFilesByName("rec.csv").next().setTrashed(true);
}
Example of other sheet code that works consistently
function ImportSmallsCSVfromDrive() {
const csvFolderName = 'FolderName';
var file = DriveApp.getFilesByName("smalls.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('smalls');
sheet.clearContents();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
DriveApp.getFilesByName("smalls.csv").next().setTrashed(true);
}
Ultimately, I am at a loss here as everything looks like it should be working but yet I still have renaming inconsistencies with my batch script and failed executions on my apps script. What am I missing?

File locks are often problems when you're changing a file on a schedule. You can prove this by copying the files before the scheduled rename. Copying will often succeed while files are locked and then changes can be made.
This may not fit your business case (maybe you can't copy them first) but it will help you identify the problem.
You can add this to your robocopy to log while scheduled. You should get a detailed error message for the failed files.
>> c:\log.txt

Related

Script Can't Open Document (Inaccessible, Please Try Again)

I'm trying to create a copy of a document and populate it with data from a spreadsheet. I can successfully create the copy but the script can't seem to access it to edit its contents. Here's the code:
var file = DriveApp.getFileById('1mWFhZpZVJpYJleg9n5qq3tr7EHwUIlbM');
var copy = file.makeCopy('SKPembimbing_' + nim, folder).getId();
var doc = DocumentApp.openById(copy);
var body = doc.getBody();
It always gives me an error at the 3rd line when it tries to open the document for editing.
(Exception: Document is inaccessible. Please try again later.)
I saw another thread from last year with the same exact question but without a solution. I've been working all night trying to get this darn thing to work. Does it have to do with my scope? I'm running it on a trigger on edit.
I found the solution:
The template document I was copying was a .docx file, NOT a Google Doc. The copied file was thus also a .docx file so was inaccessible from the DocumentApp. All I had to do was convert it to a Google Document.

Script - DriveApp.getFilesByName - get latest version?

As title suggests
Got a script that's fetching a CSV from a specific G-Drive folder, which is currently filtering by a specific file name.
Is it possible to just say 'get the latest file' from that folder instead of searching by the specific name?
Asking because multiple copies of the same file will be uploaded into the same folder (file name is content.csv, copies will either replace that file, or no doubt be uploaded as content(1).csv etc). So, therefore, assumed just trying to 'get the latest file' would be the best way?
Script:
function importCSVFromGoogleDrive() {
var fSource = DriveApp.getFolderById('xxxxxxxxxxxxx'); // folder where files are saved
var file = DriveApp.getFilesByName("content.csv").next(); // currently searching by file name
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString()); csvData.splice(299,csvData.length-300);
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
You can order the files by date so you can list the recently uploaded files, and when you hit an already downloaded file you just stop whole process.
https://developers.google.com/drive/api/v3/reference/files/list#orderBy
Try this:
function getLatest(){
var optionalArgs = {
orderBy:"modifiedDate",
q:"title='TITLE'"
};
var files = Drive.Files.list(optionalArgs).items;
Logger.log(files);
}
This will use the Advanced Services API to search for the files and order them by date. To use this code you'll need to enable Google Advanced Services, which allows you to use the APIs directly. You should also look at the File Resource to know what properties are available. Lastly, files holds an array of the files returned by the list.

Import data from CSV file in Google Drive, to Google Sheet

I am using SAS to generate two CSV files every 24 hours. And I have used a bat script to save the generated CSV files in a folder in Google Drive. The CSV files are replaced, so there will always only be these two files in the folder.
The CSV files are seperated by "," and contain only three columns or four columns.
I want to create a direct link between a google sheet and the CSV files, so that the google sheet updates to the newest numbers automatically.
I have tried using the function "ImportData" with no luck
=IMPORTDATA("https://drive.google.com/file/d/123231jshu231731/edit?usp=sharing")
where 123231jshu231731 is the file_id.
But the error I get is
Result was not automatically expanded, please insert more columns (896).
Which does not make sense as the file only have 3 columns
Hope some have a better solution to my automatization problem
Thanks
Publishing the csv files to the web
Apparently IMPORTDATA only works for documents published to the web. Two ways you could get it to work for you would be to:
Store your csv files in a public google drive folder
Host your csv files on the web some other way - I suppose you would need to run a sever on your machine with the csv files.
However, this involves making your csv data public to anyone connected to the internet (probably something you don't want)
Keeping the csv files private
If you want your data to remain private, you could make a script that periodically loads your csv data into the spreadsheet.
Google provides a service call Google Apps Script (GAS) which would allow you to write scripts in JavaScript to preform more complex tasks in google drive.
Within GAS, you can create something called an installable trigger which you can set to run periodically on a set time interval.
Here's a basic layout of how I'd go about writing the script to upload your csv data:
function timedTrigger() {
// list the csv file ids
var baseballScoresFileId = "123231jshu231731";
var donutPricesFileId = "984732ageyn555646";
// get the spreadsheet by it's id
var ss = SpreadsheetApp.openById("the spreadsheet id");
// get the sheets you want to print the data to
var baseballSheet = ss.getSheetByName("Baseball Scores");
var donutsSheet = ss.getSheetByName("Donuts Scores");
// print the data to the first row first columnscript
printCsvData(baseballScoresFileId, baseballSheet, 1, 1);
printCsvData(donutPricesFileId, donutsSheet, 5, 2); // prints to B5
}
// This function loads the data from a csv fileId
// and prints it to the sheet starting at the cell
// located at (row, col)
// It works just like IMPORTDATA except you specify the row and col in the
function printCsvData(fileId, sheet, row, col) {
// get data from file
var data = DriveApp.getFileById(fileId).getBlob().getDataAsString();
// parse the csv string into two dimensional array
var values = parseCsvData(data);
// print the values into the range starting at row, col
sheet.getRange(row, col, values.length, values[0].length).setValues(values);
}
// This function converts a string of comma
// separated values and converts them into
// a two dimensional array
function parseCsv(string) {
var values = [];
// ...
return values;
}
I'm not quite sure how you formatted your CSV files; my best guess would be:
function parseCSV(string) {
return string.split("\n").map(function (row) {
return row.split(",");
});
}
You may need to worry about extra whitespace.
If you're not familiar with JavaScript or programming, this would be a great opportunity to learn. However, if loading the csv files isn't a dire need, just note that it may take you 5-20 hours to learn how to set up the script. Either way, good luck!
I like the Google Apps Script solution I found at digital inspiration.
function importCSVFromGoogleDrive() {
var file = DriveApp.getFilesByName("filename").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActive().getSheetByName("sheetname")
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
This differs from the IMPORTDATA() spreadsheet function in that it will overwrite data already present in your spreadsheet. The first time you run the function, you will need to authorize it to read your Drive files and modify your spreadsheet. After you authorize it, you can add a trigger to make it run every time you open the spreadsheet for editing.
To import data from a .CSV file on Google Drive, which got automatic updated on an hourly basis, you should use the follow function in a cell.
=IMPORTDATA("https://drive.google.com/uc?export=download&id=KEY_DRIVE_FILE")
Google spreadsheet will fetch the data from this file now every hour (you can't adjust this. It just lookup once an hour at this file).
The 'export=download' option in the URL does the trick. You will get an exact copy of your .CSV in your spreadsheet.
The key of your Google-drive file you can found in the URL
The KEY_DRIVE_FILE (The key of your Google drive file) can be found in the url, usealy after the part where
In this picture a spreadsheet is used, but it works the same for any file.
The file should probably put in a the public folder of drive.
KEY_DRIVE_FILE could be gotten by share Drive function to get the link (no need to share actually).

Searching current folder for spreadsheets and changing value in specific cell of each file found

New to Google Apps script here, but have some coding experience. I want to scan current folder for spreadsheets. For each spreadsheet found, I want to change the value in a specific cell (say cell F16 in "Sheet1") to "Q1 FY16". Here is what I have so far:
function myFunction() {
var folderID ="0BxfGszImm3D9flpVlWXd4bjQ";
var topFolder = DriveApp.getFolderById(folderID);
Logger.log(topFolder.getName());
var filesList = topFolder.getFiles();
while (filesList.hasNext()) {
var file = filesList.next();
Logger.log(file.getName());
file.getSheetByName("Sheet1").getRange("F16").setValue("Q1 FY16");
}
}
There are two main problems:
I have to specify a folder ID in this and I don't want to. I want the code to run in the current directory (and eventually I will make it recursive to scan all subfolders as well).
The File class doesn't have the "getSheetByName()" or "getRange()" methods, but I don't know how to cast the files into Spreadsheets.
Any help with this would be greatly appreciated.
Cheers
Where will you be launching this script from? They are no way of launching script directly from google drive.
to Be able to use the getSheetByName() and the getRange() you need to open the file as a spreadsheet.
instead of using this line:
file.getSheetByName("Sheet1").getRange("F16").setValue("Q1 FY16");
You should use something like this :
try {
SpreadsheetApp.openById(file.getId()).getSheetByName("Sheet1").getRange("F16").setValue("Q1 FY16");
}
catch(e){}
you need to use the try - catch since some of the files won't be spreadsheet and give and error when trying to use the SpreadsheetApp.openById().
I hope this helps you a bit, I'll try to update this answer once I get more information for the first part.
Best of luck.

Delete or Trash specific file in Drive

I had a script that ran every day at 5 am, that would move a specific file (data.xls) to the trash. However, since DocsList has been retired, the script no longer functions, and I'm having trouble updating it.
I've seen a couple of delete/setTrashed scripts posted here, but they all seem to function for an array of files, and i only want one specific file deleted.
I'm not a coder, and self-taught myself most of the small amount i have, so i need it as simple as possible (sorry.)
Any and all help or guidance is very appreciated. Thank you.
function myFunction() {
var files = DriveApp.getFilesByName('data');
while (files.hasNext()) {
var file = files.next();
ID = file.getId(file)
Drive.Files.remove(ID);
}
}
I've seen a couple of delete/setTrashed scripts posted here, but they
all seem to function for an array of files, and i only want one
specific file deleted.
Simply put, to delete a single file you delete the first item in the list, what you are calling an array and what Google calls a file iterator.
Retrieving a file by name is going to return a list(iterator), even if it has only one file by that name, so you must treat the single item as the first item in the iterator and set that first item to trash.
Edit:
function myFunction() {
var files = DriveApp.getFilesByName('data');
while (files.hasNext()) {
files.next().setTrashed(true);
}
}
if you know that there is one and only one file by that name you could do something as simple as:
function myFunction() {
DriveApp.getFilesByName('data').next().setTrashed(true);
}
Since this is the first hit for Googling "apps script move file to trash", I found the following easy solution:
let file = DriveApp.getRootFolder().createFile('RIP file.txt', 'Good-bye, world ㅜㅜ');
file.setTrashed(true); // So the file is deleted after 30 days
File documentation
I have workaround using DriveApp removeFile. Note this does not delete or trash the file in the user archive, but is no longer visible in the named folder.
removeFile(child)
Removes the given file from the root of the user's Drive. This method
does not delete the file, but if a file is removed from all of its
parents, it cannot be seen in Drive except by searching for it or
using the "All items" view.
DriveApp.getFolderById(DriveApp.getFolderById(folderId)).removeFile(DriveApp.getFileById(fileId))