GASでスプレッドシートを新規作成する方法

GAS

※本記事はプロモーションを含みます

目次

業務システムから定期的に抽出したCSVや日次データを、既存の管理表に追記するのではなく、日付ごとや案件ごとに独立した別ファイルとして納品・共有したい場面は日常的に発生します。なので、GASでスプレッドシートを新規作成する処理を組み込むことで、手作業でファイルを作成してリネームし、権限を付与してリンクを送るという一連の退屈なルーチンを完全に無人化できます。ただし、いざスクリプトを書き始めると、多くの人が最初に生成されたファイルの「保存場所」と「後始末」で頭を抱えることになります。

createを呼んだ瞬間にマイドライブ直下に散らかる落とし穴

スプレッドシートを新しく立ち上げる命令としてSpreadsheetApp.create()が用意されています。ただし、このメソッドには直感と乖離しやすい挙動があります。というのは、引数にフォルダIDを渡すことができず、実行すると必ずマイドライブのルート階層にファイルが生成される仕様だからです。

普段デスクトップやGoogleドライブで作業するとき、私たちはまず目的の案件フォルダや月次フォルダを開きます。なので、その中で「新規作成」をクリックしてファイルを作ります。そのため、プログラム上でも「第1引数にファイル名、第2引数に保存先フォルダのIDを指定するのではないか」と考えがちです。ただし、GASのSpreadsheetApp.create()はファイル名しか受け取れません。行数や列数を初期指定するオーバーロードはあります。なので、格納先フォルダを指定する引数は存在しないのです。

この仕様を意識せずに日次バッチ処理などでSpreadsheetApp.create()を毎日動かし続けるとどうなるでしょうか。気付いたときには実行者のマイドライブ直下に数十個、数百個ものスプレッドシートが無秩序に並びます。なので、本来のマイドライブが完全に埋もれてしまいます。ただし、さらに悪いことに、Googleドライブの検索性はルートに大量の同名ファイルや似たような日次ファイルが存在すると著しく低下します。というのは、どれが最新の原本なのか見分けがつかなくなるからです。

また、チームで共有ドライブを運用している環境では、この挙動がさらに深刻な問題を引き起こします。共有ドライブ内で動かしているつもりだったスクリプトが、実は実行した個人アカウントのマイドライブ直下にファイルを作ってしまっています。なので、チームの他メンバーから「ファイルが生成されていない」「権限がなくてアクセスできない」という問い合わせが頻発する原因になります。作成自体は1行で完了する非常にシンプルなメソッドです。ただし、保存場所のハンドリングを怠ると、運用開始直後にドライブ構造が破綻するリスクを孕んでいます。

最小構成で動かす新規作成とURL取得

まずは基本となる最小限のコードから確認しましょう。この処理を単体で使う場面は、手動実行で一時的な作業用ファイルを作りたいときや、生成したスプレッドシートのWebアドレスを即座に取得して後続処理に引き渡したいときです。生成されたオブジェクトに対して直ちに操作を行える点が、手動操作にはないプログラムならではの強みです。

function createNewSpreadsheet() {
  // 指定した名前でマイドライブ直下に新しいスプレッドシートを作成する
  const newSs = SpreadsheetApp.create("新規ファイル");

  // 作成したファイルのURLを取得してログに出力する
  const fileUrl = newSs.getUrl();
  Logger.log("作成されたファイルのURL: " + fileUrl);
}

上記のコードを実行すると、Googleドライブのマイドライブ直下に「新規ファイル」という名前のシートが即座に生成されます。なので、実行ログにそのファイルの閲覧用URLが出力されます。createメソッドは、指定した名前で新しいファイルを作成します。というのは、その戻り値として生成されたSpreadsheetオブジェクトをそのまま返すからです。なので、変数newSsに受け取った直後から、シートの追加やデータの流し込み、フォーマットの調整をそのままチェーンして記述することが可能です。

ここで重要なのがnewSs.getUrl()です。業務自動化において、新しく作ったファイルの所在を人間に伝える手段は不可欠です。チャットツールに完了通知を飛ばしたり、依頼元へメールで納品報告を送ったりする際、このgetUrl()で取得した文字列を本文に埋め込みます。なので、受信者はリンクをクリックするだけで完成した成果物に直接アクセスできます。

ただし、この最小構成のままでは前述した「マイドライブ直下に放置される問題」が残ります。なので、ファイル名が「新規ファイル」と固定値になっている場合、2回目以降の実行でも同じ名前のファイルが別物として次々に増殖していく点にも注意しましょう。Googleドライブは同名ファイルの重複作成を許容するシステムです。というのは、OSのローカルファイルシステムのように「同名ファイルが存在するため上書きしますか?」といった警告を出してくれないからです。同じ名前のファイルが何十個もマイドライブに並ぶ事態を防ぐためにも、実務では動的な命名規則とフォルダ移動の処理が必須セットとなります。

特定フォルダへ確実に格納するためのDriveApp併用

マイドライブ直下にファイルが散らばる現象を回避するためには、スプレッドシートを専門に扱うSpreadsheetAppだけでなく、ドライブの階層構造やファイル配置を制御するDriveAppを併用しましょう。作成自体はSpreadsheetApp.create()で行います。なので、作られた直後にそのファイルを目的のフォルダへ移動させるという2ステップの設計を取ります。

以前のGAS(旧Drive API)では、フォルダに対してaddFile()で追加し、マイドライブのルートからremoveFile()で親参照を外すという、少し直感に反する「ラベル付け」に近い操作が必要でした。ただし、現在のGAS実行環境(V8ランタイム)では、DriveAppのFileオブジェクトにmoveTo()メソッドが用意されています。というのは、これを使うことでローカル環境のファイル移動と同じ感覚で目的の格納先フォルダへ一発で移動できるからです。

実際のコードでは次のように組み立てましょう。まず目的の保存先フォルダのIDを事前に定数として定義しておきます。なので、SpreadsheetApp.create()でファイルを生成します。続いて生成されたスプレッドシートのIDを取得します。というのは、DriveApp.getFileById(newSs.getId())を経由してファイルオブジェクトを取り出し、ターゲットフォルダに対してmoveTo()を呼び出すためです。

function createAndMoveSpreadsheet() {
  // 保存先としたいフォルダのIDを指定
  const targetFolderId = "1a2b3c4d5e6f7g8h9i0j-XXXXXXXXXXXX";
  
  // ファイル名に日付を付与して一意性を保つ
  const today = Utilities.formatDate(new Date(), "Asia/Tokyo", "yyyyMMdd");
  const fileName = "日次レポート_" + today;
  
  // 1. スプレッドシートを新規作成(この時点ではマイドライブ直下)
  const newSs = SpreadsheetApp.create(fileName);
  const newSsId = newSs.getId();
  
  // 2. DriveAppを使って目的のフォルダへ移動
  const targetFolder = DriveApp.getFolderById(targetFolderId);
  const driveFile = DriveApp.getFileById(newSsId);
  driveFile.moveTo(targetFolder);
  
  // 3. 移動後のURLを取得してログ出力
  Logger.log("格納先URL: " + newSs.getUrl());
}

この流れを踏むことで、GASでスプレッドシートを新規作成する処理が完了した段階で、ファイルは最初から目的のフォルダに作られていたかのように整然と収まります。実行者のマイドライブを汚すこともなくなります。なので、フォルダ単位でアクセス権限を設定している共有環境でも、作成と同時にフォルダの権限が自動的に継承されます。ただし、メンバーへの閲覧・編集権限の付与漏れも防げるか確認しましょう。

大量生成による容量圧迫と権限エラーを未然に防ぐ

自動生成の仕組みが整うと、ボタンひとつやタイマートリガーでスプレッドシートが次々と作られるようになります。ただし、ここで次に直面するのが運用の健全性に関わる問題です。特に見落としがちなのが、共有ドライブの制限、GoogleアカウントのAPIクォータ、そして意図しない権限漏洩のリスクです。

第1に、共有ドライブへファイルを移動させる場合の注意点です。上記のmoveTo()処理を行う際、保存先が個人の通常フォルダではなくGoogle Workspaceの「共有ドライブ」配下である場合があります。なので、実行するアカウントにその共有ドライブに対する十分な権限(投稿者以上の権限)が付与されていないと、スクリプトは権限不足のエラー(Access Denied)で停止します。管理者アカウントでテストしたときは正常に動きました。ただし、一般メンバーのアカウントやサービスアカウントでトリガー実行させた途端に失敗する典型例がこれです。自動化を設計する際は、スクリプトの実行主体が保存先フォルダに対して確実に書き込み・移動を行える権限を持っているか確認しましょう。

第2に、生成されたファイルのライフサイクル管理です。日次や案件ごとにファイルを独立して生成する運用は、データの混同を防ぐ意味では非常に安全です。ただし、放置すればファイル数は指数関数的に増加します。Googleドライブには無制限にファイルを放り込めるわけではありません。というのは、共有ドライブ内のアイテム総数上限(40万アイテム)や、組織全体のストレージ容量上限が存在するからです。過去の納品済みファイルや、一定期間を過ぎて参照されなくなった作業用スプレッドシートについては、定期的にアーカイブフォルダへ退避させましょう。なので、一定日数(例えば90日)経過したファイルをゴミ箱へ送るようなメンテナンス処理を別途検討しておくことが重要になります。

第3に、共有範囲の設定です。SpreadsheetApp.create()で作成されたファイルの初期状態は、作成者のマイドライブ直下の公開設定を引き継ぎます。なので、通常は「非公開(作成者のみ)」となります。目的のフォルダへ移動させれば基本的にはフォルダの共有設定が継承されます。ただし、社外のクライアントへ納品するために「リンクを知っている全員が閲覧可能」に切り替えたい場合などは、移動後にdriveFile.setSharing()を明示的に呼び出して共有スコープを変更しましょう。このステップを自動化に含めておかないと、クライアントにURLだけが送信されます。なので、開こうとすると「アクセス権をリクエスト」画面が表示されてしまい、納品フローが停滞することになります。

独立切り出しファイルとして納品・共有する実務フロー

システムから出力されたマスターデータや、社内用の集計シートから必要な部分だけを抜き出して顧客や他部署へ渡す場合、元のスプレッドシートをそのまま共有するわけにはいきません。というのは、他顧客の情報や社外秘の計算式、原価データなどが含まれているからです。このような場面こそ、空の新規スプレッドシートを動的に立ち上げ、公開可能なデータだけをコピーして完成させる「独立切り出し」のパターンが最も効果を発揮します。

実務でこのフローを構築する際は、単にファイルを作って移動するだけではありません。なので、元シートからのデータ転記、不要な初期シートの整理、そして最終的なリンクの通知までをひとまとまりのトランザクションとして設計しましょう。実はSpreadsheetApp.create()で生成されたばかりのファイルには、デフォルトで「シート1」という名前の空のシートが1枚だけ含まれています。元データからシートごとコピー(copyTo)して持ってくる場合、この初期シートが残ったままになります。ただし、これでは成果物を受け取った側から見て「余計な空シートが最初にある不格好なファイル」に見えてしまいます。

タイトルとURLをコピーしました