使用 Google 脚本导出 Chromebook 设备列表

问题描述 投票:0回答:1

我创建此函数是为了通过 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

google-apps-script google-sheets google-workspace chromebook
1个回答
0
投票

我绝不是 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 中,而不是表格中。

© www.soinside.com 2019 - 2024. All rights reserved.