見出し画像

[GAS]Googleドライブの共有ドライブの各フォルダの容量をスプレッドシートに一覧出力する

はじめに

諸々事情があって会社のGWSのGoogleドライブ(共有ドライブ)をBoxに移行することになりました。
移行担当者「移行計画を立てたいのでGoogleドライブの第3階層までのフォルダの一覧とその容量の一覧が欲しい」
共有ドライブの第1階層についてはGWS管理コンソールから確認はできるが第2階層以下のフォルダについては知る術がない(はず)のでGASを使って一覧化&集計することにしました。

注意点

今回は時間もなかったので、他人の作った参考ソースを元にChatGPTに「これをあーして、こーして、エラーが出たんだけど直して」と煮込み、自身でソースもろくに読まないというエンジニアのプライドを捨て去った作品なので、このページを見た皆さんはできれば真似しないでください。
(少しは中身を読み理解するのが通常)
それゆえ完成ソースにプライドも責任もございませんので皆さんご自由にお使いくださいませ

作り方

材料

1.参考ページ
クラウドネイティブさんの「GWS × GAS:共有ドライブファイル/フォルダ一覧と共有状態を出力」(https://blog.cloudnativco.jp/19298/
2.ChatGPT
ご存知の通り。

作り方

基本的な流れは参考ページの通り。
今回は流すスクリプトが違うだけなので、流すスクリプトをChatGPTにどうプロンプトにて修正させてたかを記します。

  1. 参考ページのソースをGPTに食わせます。

  2. プロンプト(以下、プ)でChatGPT(以下、G)にソースを書かせます。

プ「このコードで各ファイルサイズも取得するよう追記して」
G「こちらでどうですか?」
プ「提案のコードで以下エラーが返ってきたよ」
G「修正します。」
プ「NN行目でエラー」
G「申し訳ございません」
プ「Google共有ドライブ第三階層までのファイルをサルベージする処理に変更して」
G「こちらでどうですか?」
プ「いいね。スプレッドシートに出力する際にbyteをGB表記に変更して、ファイル/フォルダ名は階層の分だけ先頭にスペースを追記して」
G「こちらでどうですか?」
プ「出力するスプレッドシートに、編集権限ユーザー、閲覧権限ユーザー 、公開状態、PermissionCheck Statusの列は不要。」
G「こちらでどうですか?」
プ「スプレッドシートのGB列の右列にMBの列を追加して」
G「こちらで。。。」
プ「スプレッドシートのフォルダでcheckedとしている箇所をURLになるように書き換えて」
G「こ」
プ「3階層で4階層以下をまとめようとサルベージすると再帰的にIF文をグルグル回すことになってterminated errorが起こりやすくなるから、もういっそのこと7階層まで掘り進めて一覧にして」
G「それはいい提案ですね!(などとは言っていいないがこれが今回唯一私の閃きポイント)」
その他スプレッドシートの体裁とかを色々直させて…

できたスクリプトがこちらです。

const SPREADSHEET_ID = '181EHgY-XtR-pDTs-o_ivu1_6ZSFe6elhPlkXiEzK-Nc'; // スプレッドシートのIDに変更
const SHARED_DRIVE_ID = '1jQhV2hvG-5tE7wwwp3XADL53ATFk8jCd'; // 共有ドライブのIDに変更
const MAX_EXECUTION_TIME = 1740000;
const BATCH_SIZE = 100; // バッチ処理のサイズ
const MAX_DEPTH = 7; // 処理する階層の深さ
const scriptProperties = PropertiesService.getScriptProperties();
let existingData = []; // 既存のデータを保持する配列
function listFilesInSharedDrive() {
  let startTime = new Date().getTime();
  const sheet = getOrCreateSheet();
  const rootFolder = DriveApp.getFolderById(SHARED_DRIVE_ID);
  // 既存のデータを取得
  existingData = sheet.getDataRange().getValues();
  // 共有ドライブの直下に存在するフォルダとファイルを取得
  processFolder(rootFolder.getUrl(), sheet, 0);
  // 処理が完了したことを示すメッセージをシートに追加
  sheet.appendRow(['', '処理が完了しました', '', '', '', '']);
  scriptProperties.deleteProperty('last_processed_folder');
}
function processFolder(folderUrl, sheet, depth) {
  if (depth >= MAX_DEPTH) return; // 指定された階層を超える場合には処理を終了
  const folderId = getFolderIdFromUrl(folderUrl);
  if (!folderId) {
    Logger.log('folderIdがみつかりません:' + folderUrl);
    return;
  }
  const folder = DriveApp.getFolderById(folderId);
  const folderPath = getFolderPath(folder);
  // フォルダ内のフォルダ一覧とファイル一覧を取得
  const subFoldersAndFiles = [];
  const folders = folder.getFolders();
  while (folders.hasNext()) {
    const subFolder = folders.next();
    subFoldersAndFiles.push([addIndentation(subFolder.getName(), depth), 'フォルダ', subFolder.getUrl(), folderPath + '/' + subFolder.getName(), '', '']);
  }
  const files = folder.getFiles();
  while (files.hasNext()) {
    const file = files.next();
    const fileSizeGB = convertBytesToGB(file.getSize()); // ファイルサイズをGBに変換
    const fileSizeMB = convertBytesToMB(file.getSize()); // ファイルサイズをMBに変換
    subFoldersAndFiles.push([addIndentation(file.getName(), depth), 'ファイル', file.getUrl(), folderPath + '/' + file.getName(), fileSizeGB, fileSizeMB]);
  }
  // バッチ処理でシートへ記載する
  writeBatchDataToSheet(sheet, subFoldersAndFiles);
  // 再帰的にサブフォルダを処理
  subFoldersAndFiles.forEach(entry => {
    if (entry[1] === 'フォルダ') {
      processFolder(entry[2], sheet, depth + 1);
    }
  });
  // フォルダのチェック状態を更新
  updateFolderCheckStatus(sheet, folderUrl);
}
function getOrCreateSheet() {
  const sharedDriveName = DriveApp.getFolderById(SHARED_DRIVE_ID).getName();
  let sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(sharedDriveName);
  if (!sheet) {
    sheet = SpreadsheetApp.openById(SPREADSHEET_ID).insertSheet(sharedDriveName);
    initializeSheet(sheet);
  }
  return sheet;
}
function initializeSheet(sheet) {
  sheet.appendRow(['ファイル/フォルダ名', 'タイプ', 'URL', 'パス', 'サイズ (GB)', 'サイズ (MB)']);
}
function writeBatchDataToSheet(sheet, data) {
  const newData = data.filter(row => !existingData.some(existingRow => existingRow.join() === row.join()));
  if (newData.length > 0) {
    sheet.getRange(sheet.getLastRow() + 1, 1, newData.length, newData[0].length).setValues(newData);
    existingData = existingData.concat(newData); // 既存のデータに新しいデータを追加
  }
}
function getFolderPath(folder) {
  const folderPath = [];
  let currentFolder = folder;
  while (currentFolder.getId() !== SHARED_DRIVE_ID) {
    folderPath.unshift(currentFolder.getName());
    currentFolder = currentFolder.getParents().hasNext() ? currentFolder.getParents().next() : null;
  }
  return folderPath.join('/');
}
function updateFolderCheckStatus(sheet, folderUrl) {
  const folderId = getFolderIdFromUrl(folderUrl);
  const folder = DriveApp.getFolderById(folderId);
  const folderPath = getFolderPath(folder);
  const rowIndex = existingData.findIndex(row => row[2] === folderUrl);
  if (rowIndex !== -1) {
    existingData[rowIndex][3] = folderPath; // 行の4番目にフォルダのパスを記録する
    const range = sheet.getRange(rowIndex + 1, 4);
    range.setValue(folderPath);
  }
}

function getFolderIdFromUrl(url) {
  const pattern = /drive\/folders\/([^\/?]+)(?:\?|$)/;
  const match = url.match(pattern);
  return (match && match[1]) ? match[1] : null;
}
function convertBytesToGB(bytes) {
  return (bytes / (1024 ** 3)).toFixed(2); // ギガバイトに変換して少数第二位まで表示
}
function convertBytesToMB(bytes) {
  return (bytes / (1024 ** 2)).toFixed(2); // メガバイトに変換して少数第二位まで表示
}
function addIndentation(name, depth) {
  return ' '.repeat(depth * 2) + name; // 階層に応じたスペースを追加
}

スプレッドシートの一部

こんな感じ

Drive_ID毎にシートができるのでスプレッドシートに別途集計シートを作成して各出力シートのE列なり、F列をSUMしてください。
集計シートとGWS管理コンソールでの第1階層のデータ容量がを比較して相違がなければこのスクリプトのミッションは完了です。
今回弊社は全部で数10TBあり、GWS管理コンソールのデータ容量と一致したので目的は達成されました。

さいごに

以上が今回時間がない中、エンジニアとしてのプライドを投げ捨ててChatGPTにスクリプトを直させてGAS実行し、Googleドライブ(共有ドライブ)のフォルダ一覧および容量の集計が完了しました。
もっと時間があればソースの内容を推敲したり、出力するスプレッドシートももっとスマートにできたやもしれません。
それはまたこの記事を見たあなたに託しますw
それではまた。

いいなと思ったら応援しよう!