我创建此函数是为了通过 Google 管理门户导出 Chrome 设备列表。它按 PRE_PROVIONED 状态收集设备和过滤器。然而,当尝试运行所有页面(130,000 个设备)时,出现错误“内存不足错误”。正在被退回。如何修复这个错误?如果我删除分页(nextPageToken),它就可以正常工作。
function exportChromebooksToSheet() {
// Adicione os escopos necessários
const maxResults = 50; // ajuste conforme necessário
let pageToken;
const allDevices = [];
do{
const options = {
orderBy: 'serialNumber',
maxResults: maxResults,
pageToken: pageToken
};
// Obtenha a instância do serviço de Administração
const response = (AdminDirectory.Chromeosdevices.list("my_customer", options));
let devices = response.chromeosdevices;
// Adicione os dispositivos da página atual à lista completa
allDevices.push(...devices);
// Atualize o token de página para a próxima página
pageToken = response.nextPageToken;
} while (pageToken);
// Filtrar dispositivos com status PRE_PROVISIONED
const preProvisionedDevices = devices.filter(function(device) {
return device.status === 'PRE_PROVISIONED';
});
writeToSheet(preProvisionedDevices);
}
function writeToSheet(devices) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Limpe o conteúdo atual da planilha
sheet.clear();
// Escreva os cabeçalhos
var headers = ['Serial Number', 'Status'] // Adicione mais campos conforme necessário
sheet.appendRow(headers);
// Escreva os dados dos dispositivos
devices.forEach(function (device) {
var rowData = [
device.serialNumber,
device.status,
// Adicione mais campos conforme necessário
];
sheet.appendRow(rowData);
});
}
我尝试使用不同的参数设置 maxResults 但没有任何反应。如果我删除 pageToken 并将 maxResults 设置为任何值,它总是返回 42
我绝不是 Apps 脚本方面的专家,但以下是我在我的组织中解决此问题的方法。
我确实想首先提到,如果自动化不是您的目标,供应商的 sheet 插件(称为 Gopher)可以执行您所要求的操作,只是不能自动执行。
现在对于自动化来说,这增加了一些复杂性。发生该错误的原因是您的数组“allDevices”包含太多设备,Apps 脚本运行时无法处理它。它的大小会导致您的错误。解决方案是定期将这些设备中的一小部分转储到其他设备中,例如 Google Sheets 或 Google Drive。
现在,您将遇到的第二个问题是,由于您拥有超过 100,000 台设备,因此您最终也会收到超时错误。 Apps 脚本只能运行 30 分钟,如果您注意到,每次运行“AdminDirectory.Chromeosdevices.list”时,大约需要 2 秒,最多只返回 100 个设备。这意味着在 30 分钟内,理论上您可以获得的最大设备数为 90,000。在实践中,我得到的常常比这个少。
这意味着要解决您的问题,您将需要多次运行脚本,并将结果保存为多个较小的块。下面显示的是一些经过大量注释的伪代码,它将页面令牌存储在代码中,允许其多次运行。就我而言,每次运行脚本都会得到大约 32,000 个结果,因此我将 Apps 脚本硬编码为每晚运行 3 次。在您的情况下,您将执行尽可能多的执行,以使其在表格中工作。
// The biggest complexity is getting the script to run multiple times
// My solution is to store the page token in Drive, and use that to allow multiple runs in a row
// I do multiple runs in a row by counting how many runs I need, and then making consequtive triggers for them
// This means that if I get 30,000 results per run, then my script needs to run 3 different triggers to reach ~90,000.
// A better coder could have the script retrigger itself
const folder = DriveApp.getFolderById("INPUT_YOUR_FOLDER_HERE");
const folderdirectory = folder.getFiles();
while (folderdirectory.hasNext()) { // This loops through each file to get the page token in the folder
// I store the page token in the same folder as the Google Sheet, but you don't have to
const file = folderdirectory.next();
if (!file.getName().endsWith(".gsheet")) {// The unfinished token is not a sheet
pageToken = file.getName(); //Sets PageToken to filename of PageToken file
file.setTrashed(true); // Deletes the Page Token file to make way for a new one on next run
}
}
// Next, you need to hardcode your limit on how many devices per run. In this example, I choose 30,000
// countOfResults will start at 0 and incremement until 30,000, then stopping
let countOfResults = 0;
do {
const options = { // As mentioned later, you likely should put your preprovisioned filter here
orderBy: 'serialNumber',
maxResults: maxResults,
pageToken: pageToken
};
// Obtenha a instância do serviço de Administração
const response = (AdminDirectory.Chromeosdevices.list("my_customer", options));
let devices = response.chromeosdevices;
// We now immediately write this to sheets. This does take longer, but we now run multiple times, so it doesn't matter too much
// You can also use Sheets.getRange().setValues() to speed this up, but I could not get it to work personally
appendToSheet(devices);
countOfResults += 100;//Incremement our counter so we can stop before our time limit
// Atualize o token de página para a próxima página
pageToken = response.nextPageToken;
} while ((pageToken) && (countOfResults < 30000)); // When we run out of page tokens, the executions stop for real
// but if we've just hit the limit, we use the below code to get ready to start again
if ((typeof pageToken !== "undefined")) { // If there still is another pageToken, setup next run
//Store Page Token for next Run
const filename = String(pageToken);
folder.createFile(filename, filename);
}
}
function appendToSheet(devices) { // We can't just write it all at once, so we have to append
// You will need to write code to reset the report when a fresh start is needed, rather than an append
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); // You could use SpreadsheetApp.openById to let this always run, even if you don't have sheets open
// But if you plan to only run this script with Sheets actively open, I still recommend Gopher
// Escreva os dados dos dispositivos
devices.forEach(function (device) {
var rowData = [
device.serialNumber,
device.status,
// Adicione mais campos conforme necessário
];
sheet.appendRow(rowData);
});
}
上面的代码显示了解决错误问题所需的更改。我不会过多地将其存储在表格中,因为相对而言,这相对容易做到,并且不是问题的关键,但我确实想让您知道,您可以调用 ChromeOSDevice.list 的过滤器,例如如下图:
const options = {
"maxResults": 100,
"pageToken": pageToken,
"query": "status:managed",
"projection": "BASIC"
}
// Get devices from Admin Directory
const response = AdminDirectory.Chromeosdevices.list('XXXXXXX', options);
我没有表格示例代码的主要原因是我将其存储在我的组织的 JSON 中,而不是表格中。