指定したDriveフォルダから、ファイル名・閲覧URL・ファイルIDを一覧にします。
走査が終わってから新しい結果シートを作るため、既存の一覧へ追記・上書きしません。
最終確認は2026年10月2日です。
ローカルの模擬検証を行いましたが、Googleへの認可・実シートへの反映・Driveの実ファイル列挙・Webアプリの配備は未検証です。
練習用の入力と設定
ZIPを展開し、使う記事のarticle-353.jsだけをApps Scriptへ保存します。
同名の関数を含むため、別の記事のコードを同じプロジェクトへ混ぜないでください。
| 設定名 | 設定する値 |
|---|---|
| FOLDER_ID | 閲覧できる少数ファイルの練習フォルダID |
| SPREADSHEET_ID | 練習用スプレッドシートID |
| RECURSIVE | 直下だけはfalse。子フォルダも含める場合はtrue |
プロジェクトの設定でスクリプトプロパティを入力します。
まず新規の練習データを使い、要求される認可範囲と操作内容を確認してください。
入力例と実行する関数
親フォルダにAを1個、子フォルダにBを1個入れた練習例を使います。
RECURSIVE=falseの結果は1行、trueは2行です。
exportFilesで新しい結果シートを作り、名前・URL・IDを照合します。
// このコードは記事ごとに別のApps Scriptプロジェクトへ保存します。
function required_(key) {
const value=PropertiesService.getScriptProperties().getProperty(key);
if (!value) throw new Error(key+'を設定してください');
return value;
}
function safeCell_(value) {
const s=String(value);
return /^[=+@-]/.test(s) ? "'"+s : s;
}
function escapeHtml_(value) {
return String(value).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
}
function https_(value) {
const s=String(value).trim();
if (!/^https:\/\/[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?(?::443)?(?:[/?#][^\s<>"'\\]*)?$/i.test(s)) throw new Error('HTTPS URLを確認してください');
return s;
}
function sourceSheet_() {
const sheet=SpreadsheetApp.openById(required_('SPREADSHEET_ID')).getSheetByName(required_('SHEET_NAME'));
if (!sheet) throw new Error('対象シートがありません');
return sheet;
}
function walkFolder_(root,recursive) {
const queue=[{folder:root,path:root.getName()}],seen=new Set(),rows=[],counts=[];
let visitedFiles=0;
for (let index=0;index<queue.length;index++) {
if (index>=100) throw new Error('100フォルダを超えるため中止しました');
const {folder,path}=queue[index],id=folder.getId();
if (seen.has(id)) throw new Error('重複フォルダIDです');
seen.add(id);
const files=folder.getFiles();let count=0;
while (files.hasNext()) {
const file=files.next();
if (++visitedFiles>1000) throw new Error('1000ファイルを超えるため中止しました');
rows.push([safeCell_(path),safeCell_(file.getName()),file.getUrl(),file.getId()]);count++;
}
counts.push([safeCell_(path),id,count]);
if (recursive) {
const children=folder.getFolders();
while(children.hasNext()) {
const child=children.next();queue.push({folder:child,path:path+' / '+child.getName()});
if(queue.length>100) throw new Error('100フォルダを超えるため中止しました');
}
}
}
return {rows,counts,total:visitedFiles};
}
function createOutput_(header,rows) {
// 走査完了後だけ、新規の空シートへ一括出力します。
const ss=SpreadsheetApp.openById(required_('SPREADSHEET_ID'));
const name='練習結果_'+Utilities.getUuid().replace(/-/g,'');
const sheet=ss.insertSheet(name);
if(sheet.getMaxRows()<rows.length+1) sheet.insertRowsAfter(sheet.getMaxRows(),rows.length+1-sheet.getMaxRows());
sheet.getRange(1,1,rows.length+1,header.length).setValues([header,...rows]);
return name;
}
function recursive_(){return PropertiesService.getScriptProperties().getProperty('RECURSIVE')==='true';}
function previewFiles() {
const result=walkFolder_(DriveApp.getFolderById(required_('FOLDER_ID')),recursive_());
Logger.log('ファイル件数: '+result.total);return result;
}
function exportFiles() {
const result=previewFiles();
return createOutput_(['フォルダパス','ファイル名','閲覧URL','ファイルID'],result.rows);
}
確認結果と切り分け
| 条件 | 結果 |
|---|---|
| 空フォルダ | 新しい結果シートに見出しだけを出力 |
| 再実行・同名ファイル | 別の新規結果シート。IDで区別し古い行を混ぜない |
| 上限・権限エラー | 走査が失敗した場合は結果シート作成前に停止 |
Node.jsの模擬検証は5記事合計69ケースです。
純粋関数の結果と、模擬のGoogleオブジェクトで対象選択・書込先・失敗時停止を確認した範囲であり、実サービスの成功を示すものではありません。
100フォルダまたは1000ファイルを超える対象は走査を止めます。
この上限以内でもApps Scriptの実行時間や認可で停止する場合があります。
途中再開はなく、共有ドライブやショートカットのリンク先、見えないファイルを含む網羅的な棚卸しは未確認です。
ファイル名の先頭が数式として解釈される記号なら文字列として出力します。
Driveの共有範囲は変更せず、閲覧URLを取得しても他のユーザーへ閲覧権限を与えることにはなりません。
停止と戻し方
この例は定期トリガーを作成しません。
既存トリガーから呼ぶ変更を加える場合は、まず手動の1回を確認し、停止時にはそのトリガーを止めます。
結果シートは毎回新規です。
書込時の失敗で途中結果が残る場合は完成した一覧として使わず、既存の元データと混ぜないでください。
結果の削除や古いシートの一括消去はコードに含めていません。
公式資料
Driveフォルダの取得と列挙、シート範囲への反映、HTMLへの出力とエスケープ、Apps Scriptの利用上限を参照してください。
関連記事・旧実装の参考資料
従来のコードや外部の参考例は、本稿の練習ZIPと内容が異なる場合があります。
今回のコードは記事ごとに別のプロジェクトへ保存してください。




