Google Sheets转PDF存Drive脚本共享后报访问拒绝错误
问题描述
- 使用本人Gmail账号运行绑定Google表格的脚本时,功能可正常执行
- 将关联脚本的Google表格共享给其他Gmail账号后,脚本运行持续报错
- 报错信息:
Exception: Access denied: DriveApp.
现有脚本实现逻辑:将指定工作表导出为PDF格式,保存至个人Google Drive指定文件夹,同时将PDF作为附件发送给指定联系人。
目标需求:其他用户获得工作表使用权限时,代码可正常运行,解决上述权限报错。
原始代码
function sendReport(range) { SpreadsheetApp.getActive().getSheetByName("Customers").hideSheet(); SpreadsheetApp.getActive().getSheetByName("Products").hideSheet(); SpreadsheetApp.getActive().getSheetByName("SO Log").hideSheet(); SpreadsheetApp.getActive().getSheetByName("SOF").hideSheet(); var ss = SpreadsheetApp.getActiveSpreadsheet(); var SOSheet = ss.getSheetByName("Sales Order"); var name = SOSheet.getRange('F10').getValue(); var message = { to: "random@gmail.com", subject: "Sales Order", body: "Hi team,\n\nPlease find the Sales Order attached.\n\nThank you", name: "Dave", attachments: [SpreadsheetApp.getActiveSpreadsheet().getAs(MimeType.PDF).setName("SO"+name)] } MailApp.sendEmail(message); SpreadsheetApp.getActive().getSheetByName("Customers").showSheet(); SpreadsheetApp.getActive().getSheetByName("Products").showSheet(); SpreadsheetApp.getActive().getSheetByName("SO Log").showSheet(); SpreadsheetApp.getActive().getSheetByName("SOF").showSheet(); var ss = SpreadsheetApp.getActiveSpreadsheet(); var token = ScriptApp.getOAuthToken(); var sheet = ss.getSheetByName("Sales Order"); var bogus = DriveApp.getRootFolder(); //Creating an exportable URL var url = "https://docs.google.com/spreadsheets/d/SS_ID/exSOrt?".replace("SS_ID", ss.getId()); var folderID = "1KU7ylGsci9qsVzxU2ZlCW"; // Folder id to save in a folder. var folder = DriveApp.getFolderById(folderID); var SOcode = ss.getRange("'Sales Order'!F10").getValue() var pdfName = "SO" + SOcode; /* Specify PDF export parameters */ var url_ext = 'exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx + '&size=A4' // paper size legal / letter / A4 + '&SOrtrait=true' // orientation, false for landscape + '&fitw=true&source=labnol' // fit to page width, false for actual size + '&sheetnames=false&printtitle=false' // hide optional headers and footers + '&pagenumbers=false&gridlines=false' // hide page numbers and gridlines + '&fzr=false' // do not repeat row headers (frozen rows) on each page + '&gid='; // the sheet's Id // Convert individual worksheet to PDF var response = UrlFetchApp.fetch(url + url_ext + sheet.getSheetId(), { headers: { 'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()},muteHttpExceptions:true}); ; var blobs = response.getBlob().setName(pdfName + '.pdf'); var folders = folder.getFoldersByName(pdfName); folder = folders.hasNext() ? folders.next() : folder.createFolder(pdfName); var newFile = folder.createFile(blobs); var newFileLink = newFile.getUrl(); var SOcode = ss.getRange("'SOF'!F12").getValue(); var writePDFLink = ss.getRange("'SOF'!L1").setValue(newFileLink); // Define the scope Logger.log("Storage Space used: " + DriveApp.getStorageUsed()); }
报错原因
- 脚本默认以当前触发操作的用户身份运行,权限和当前用户完全对齐
- 代码中硬编码的目标Drive文件夹属于你个人账号,其他被共享表格的用户默认没有该文件夹的编辑/写入权限,调用
DriveApp.getFolderById访问该文件夹时会直接触发权限拒绝 - 代码本身存在3处会导致功能异常的笔误:导出URL路径中
exSOrt拼写错误、PDF参数中SOrtrait拼写错误、URL参数连接符错误使用HTML转义字符&而非实际需要的&
解决方案
根据使用场景二选一即可:
方案1:调整文件夹权限(改动最小,适合使用人数少的场景)
- 打开个人Google Drive中ID为
1KU7ylGsci9qsVzxU2ZlCW的目标文件夹 - 将该文件夹共享给所有需要运行脚本的用户,授予编辑者权限
- 修正代码中的笔误:
- 将URL中的
exSOrt替换为export - 将参数中的
&SOrtrait=true替换为&portrait=true - 将所有
&替换为&
- 将URL中的
- 保存脚本后重新授权即可正常运行
注意:该方案下邮件会以当前运行脚本的用户身份发送,如需固定发件人为本人,请选择方案2。
方案2:部署为所有者权限运行的Web应用(无需开放个人文件夹权限,适合多用户使用场景)
- 打开脚本编辑器,点击左侧「项目设置」,勾选「在编辑器中显示"appsscript.json"清单文件」
- 回到编辑器页面,打开左侧文件列表中的
appsscript.json,补充所需权限声明,完整内容如下:
{ "timeZone": "Asia/Shanghai", "dependencies": {}, "exceptionLogging": "STACKDRIVER", "runtimeVersion": "V8", "oauthScopes": [ "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/script.send_mail" ] }
- 按方案1中的说明修正代码里的3处笔误
- 点击编辑器右上角「部署」→「新建部署」,部署类型选择「Web应用」
- 「执行身份」选择我(你的邮箱账号),「访问权限」选择「任何拥有Google账号的人」,点击完成部署,复制生成的Web应用URL
- 将表格内原来绑定
sendReport函数的按钮,改为绑定调用Web应用的触发函数即可,示例触发函数:
function triggerSendReport() { UrlFetchApp.fetch("你复制的Web应用URL", { method: "post", headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()} }) }
该方案下无论哪个用户触发操作,脚本始终以你的身份运行,天然拥有个人Drive文件夹的访问权限,不需要给其他用户开放文件夹权限,同时邮件发件人也固定为你的账号。
内容的提问来源于stack exchange,提问作者Enna Nadanthaalum
相关产品推荐
相关产品推荐

