GAS Hello World 〜スプレッドシートで処理を自動化する最初の一歩〜

Google Apps Script(GAS)で業務を自動化したいと思った時「まずはGASの何から学び始めればよいのだろう?」と迷う人は少なくないでしょう。 GASで行う「Hello World」としてスプレッドシートへ入力した名前に対して、自動であいさつを返す仕組みを作ってみましょう。
この記事では、スプレッドシートにひも付いた「コンテナバインドGAS」を使い、次の順番で処理を広げていきます。
- 同じスプレッドシート内でデータを読み書きする
- セルの編集をきっかけに、処理を自動実行する
- あるスプレッドシートから別のスプレッドシートへデータを送る
- シンプルトリガーとインストーラブルトリガーを使い分ける
コードは短めですが、GAS開発で重要な「イベント」「権限」「実行ユーザー」「上限」の基本を一通り体験できます。
この記事で解決できる課題
この記事の内容は、たとえば次のような小さな自動化の土台になります。
- 入力された担当者名に応じて、確認メッセージを表示する
- 申請シートへ入力されたデータを、集約用シートへ転記する
- 複数の案件管理シートから、管理台帳へ更新情報を集める
- 編集日時や処理結果を自動で記録する
- 手作業によるコピー&ペーストを減らす
コンテナバインドGASとは?
コンテナバインドGASとは、特定のGoogleスプレッドシート、ドキュメント、スライド、フォームにひも付いたApps Scriptプロジェクトです。「コンテナ」は、スクリプトが入っている箱となるファイルを意味します。
スプレッドシートから次の手順で作成したスクリプトは、そのスプレッドシートにバインドされます。
- Googleスプレッドシートを開く
- メニューの「拡張機能」を選ぶ
- 「Apps Script」を選ぶ
コンテナバインドGASでは、コードにスプレッドシートIDを書かなくても、SpreadsheetApp.getActiveSpreadsheet() やトリガーのイベントオブジェクトから、自分自身のスプレッドシートを取得できます。
一方、別のスプレッドシートを開く場合は、後ほど登場する SpreadsheetApp.openById() と、そのファイルへアクセスするための権限が必要です。
完成イメージ
最初に、自分のスプレッドシートだけで次の動きを作ります。
「入力」シートのA2に「佐藤」と入力
↓
↓ onEdit(e)が自動実行
↓
B2に「佐藤さん、Hello GAS!」と表示
C2に処理日時を記録次に、同じ編集内容を別のスプレッドシートへ送ります。
入力元スプレッドシート
↓
↓ インストーラブルトリガーが自動実行
↓
集約先スプレッドシートの末尾へ1行追加準備:入力用シートを作る
記事用に新しいスプレッドシートを作成し、ファイル名を「GAS Hello World サンプル」とします。 シート名を「入力」に変更し、1行目に次の見出しを入力してください。
| A列 | B列 | C列 |
|---|---|---|
| 名前 | メッセージ | 処理日時 |
Step 1:自分のスプレッドシート内で読み書きする
「拡張機能」から「Apps Script」を開き、エディタのコードを次の内容へ置き換えます。
/**
* 「入力」シートのA列が編集されたら、同じ行へメッセージと日時を書き込む。
* シンプルトリガーとして自動実行される。
*
* @param {GoogleAppsScript.Events.SheetsOnEdit} e 編集イベント
*/
function onEdit(e) {
const editedRange = e.range;
const sheet = editedRange.getSheet();
// 「入力」シートのA2以降だけを処理する
if (
sheet.getName() !== '入力' ||
editedRange.getColumn() !== 1 ||
editedRange.getRow() < 2 ||
editedRange.getNumRows() !== 1 ||
editedRange.getNumColumns() !== 1
) {
return;
}
const row = editedRange.getRow();
const name = String(editedRange.getValue()).trim();
const messageCell = sheet.getRange(row, 2);
const processedAtCell = sheet.getRange(row, 3);
// 名前が削除されたら、出力も消す
if (name === '') {
messageCell.clearContent();
processedAtCell.clearContent();
return;
}
messageCell.setValue(`${name}さん、Hello GAS!`);
processedAtCell.setValue(new Date());
}コードを保存したら、Apps Scriptエディタの「実行」ボタンは押さず、スプレッドシートへ戻ります。 「入力」シートのA2へ、次のように名前を入力してください。
佐藤B2に「佐藤さん、Hello GAS!」、C2に現在日時が表示されれば成功です。
コードのポイント
onEdit(e) は、ユーザーがスプレッドシートの値を編集したときに自動で呼び出される、特別な名前の関数です。このように、決められた関数名を書くだけで利用できる仕組みを「シンプルトリガー」と呼びます。
引数の e は「イベントオブジェクト」です。イベントオブジェクトには、どのセルが編集されたか、どのスプレッドシートで発生したかといった情報が入っています。
const editedRange = e.range;今回は editedRange.getValue() で入力された名前を読み、setValue() で同じ行のB列とC列へ値を書いています。
const name = String(editedRange.getValue()).trim();
messageCell.setValue(`${name}さん、Hello GAS!`);
processedAtCell.setValue(new Date());これで「読み取り」と「書き込み」を一つの関数で実現しています。
なぜエディタの「実行」ボタンを押さないのか?
エディタから onEdit を直接実行すると、編集イベントが発生していないため、イベントオブジェクト e が渡されません。
その結果、e.range を取得する場所でエラーになります。
onEdit(e) の動作確認は、実際にスプレッドシートのセルを編集して行います。
エラーや実行履歴は、Apps Scriptエディタ左側の「実行数」から確認できます。
シンプルトリガーでできること・できないこと
今回の onEdit(e) は、自分自身のスプレッドシート内を読み書きしています。この操作はシンプルトリガーで実行できます。
シンプルトリガーは、ユーザーへ認可画面を表示せずに自動実行されます。そのため便利な反面、認可が必要なサービスにはアクセスできません。
主な制約は次のとおりです。
- バインドされている自分自身のファイルは変更できる
- 別のスプレッドシートや別のDriveファイルにはアクセスできない
- Gmailなど、認可が必要なサービスは利用できない
- 1回の実行時間は最大30秒
- 閲覧権限やコメント権限で開かれた場合は実行されない
- 実行ユーザーのメールアドレスなどを常に取得できるとは限らない
また、GASの setValue() やAPIからセルを書き換えても、onEdit(e) は連鎖的に呼び出されません。
今回のコードがB列やC列を書き換えても onEdit(e) が無限に繰り返されないのは、この仕様のためです。
Step 2:別のスプレッドシートへデータを送る
次は、「入力」シートに追加した名前を、別の集約用スプレッドシートへ記録します。
集約先を準備する
記事用にもう一つスプレッドシートを作り、ファイル名を「GAS Hello World 集約先」とします。
シート名を「受信」に変更し、1行目へ次の見出しを入力してください。
| A列 | B列 | C列 | D列 |
|---|---|---|---|
| 連携日時 | 入力元 | 入力行 | 名前 |
次に、集約先スプレッドシートのURLからスプレッドシートIDを確認します。
https://docs.google.com/spreadsheets/d/ここがスプレッドシートID/edit記事や公開リポジトリでは、実際のIDを掲載しないようにしてください。
連携用の関数を追加する
入力元のApps Scriptプロジェクトへ、次の関数を追加します。DESTINATION_SPREADSHEET_ID は、実際の集約先IDへ置き換えてください。
/**
* 「入力」シートのA列へ入力された名前を、別スプレッドシートへ追記する。
* インストーラブル編集トリガーから呼び出す。
*
* @param {GoogleAppsScript.Events.SheetsOnEdit} e 編集イベント
*/
function syncToAnotherSpreadsheet(e) {
const editedRange = e.range;
const sourceSheet = editedRange.getSheet();
if (
sourceSheet.getName() !== '入力' ||
editedRange.getColumn() !== 1 ||
editedRange.getRow() < 2 ||
editedRange.getNumRows() !== 1 ||
editedRange.getNumColumns() !== 1
) {
return;
}
const name = String(editedRange.getValue()).trim();
if (name === '') {
return;
}
const destinationSpreadsheet = SpreadsheetApp.openById(
'DESTINATION_SPREADSHEET_ID'
);
const destinationSheet = destinationSpreadsheet.getSheetByName('受信');
if (!destinationSheet) {
throw new Error('集約先に「受信」シートが見つかりません。');
}
destinationSheet.appendRow([
new Date(),
e.source.getName(),
editedRange.getRow(),
name,
]);
}ここで使っている SpreadsheetApp.openById() は、指定したIDのスプレッドシートをサーバー上で開くメソッドです。
別のファイルへアクセスするにはユーザーの認可が必要なため、この関数をシンプルトリガーの onEdit(e) から呼び出すことはできません。
そこで、認可済みの権限で動作する「インストーラブルトリガー」を設定します。
Step 3:インストーラブルトリガーを設定する
Apps Scriptエディタで、次の手順を実行します。
-
左側の時計アイコン「トリガー」を開く
-
右下の「トリガーを追加」を選ぶ
-
実行する関数に
syncToAnotherSpreadsheetを選ぶ -
イベントのソースに「スプレッドシートから」を選ぶ
-
イベントの種類に「編集時」を選ぶ
-
「保存」を選ぶ
-
Googleアカウントを選び、必要なアクセス権を許可する トリガーを作成するGoogleアカウントには、入力元と集約先の両方に対する必要な権限を付与してください。
-
トリガーが一覧に表示されることを確認
設定後、「入力」シートのA3へ「鈴木」と入力します。 次の二つが確認できれば成功です。
-
入力元のB3とC3が更新される
-
集約先の「受信」シートへ1行追加される
同じ一回のセル編集に対して、次の二つが別々に動いています。
セルを編集
├─ シンプルトリガー onEdit(e)
│ └─ 自分のスプレッドシートを更新
│
└─ インストーラブル編集トリガー
└─ 別のスプレッドシートへ追記参考:アクセス許可例
個人アカウントで実施した場合のアクセス許可例を紹介
ダイアログが表示されるのでAdvancedをクリックして開きます。
Go to <プロジェクト名>をクリックします。
確認画面が表示されます。
Continueクリックします。
シンプルトリガーとインストーラブルトリガーの違い
違いを整理すると、次のようになります。
| 比較項目 | シンプルトリガー | インストーラブルトリガー |
|---|---|---|
| 設定方法 | onEdit(e) などの決められた関数名を書く | 画面またはコードから明示的に作成する |
| 事前認可 | 不要 | 必要 |
| 自分のファイルの操作 | 可能 | 可能 |
| 別ファイルへのアクセス | 不可 | 作成者に権限があれば可能 |
| Gmailなど認可が必要なサービス | 原則利用不可 | 権限を許可すれば利用可能 |
| 主なイベント | 開く、編集、選択変更など | 開く、編集、変更、フォーム送信、時間主導など |
| 実行権限 | 認可なしの制限された状態 | トリガーを作成したユーザーの権限 |
| 実行時間 | 最大30秒 | 通常のスクリプト実行上限の対象(現在は最大6分/回) |
| 共同編集時 | コードと一緒に共有される | 作成したトリガー自体は他ユーザーへ共有されない |
インストーラブルトリガーは「作成者の権限」で動く
インストーラブルトリガーで特に注意したいのが、実行ユーザーです。
たとえば、管理者Aさんが syncToAnotherSpreadsheet の編集トリガーを作成したとします。その後、編集者Bさんが入力元シートを編集しても、トリガーはAさんの権限で実行されます。
Bさんがセルを編集
↓
Aさんが作成したトリガーが起動
↓
Aさんの権限で集約先へ書き込むそのため、次の点を確認しておきましょう。
- トリガー作成者が集約先への編集権限を持っているか
- 作成者の退職やアカウント停止に備えた運用になっているか
- 誰がトリガーを作成したか記録しているか
- トリガー作成者へ過剰な権限を付与していないか
また、インストーラブルトリガーはプロジェクトの共同編集者へ自動共有されません。Aさんが作ったトリガーをBさんが同じ画面で管理できるとは限らないため、チームではセットアップ手順を文書化するか、トリガーを作る専用関数を用意すると管理しやすくなります。
注意:GASトリガーには上限がある
トリガーは便利ですが、作成数や実行時間には上限があります。
| 項目 | 個人向けGoogleアカウント | Google Workspace |
|---|---|---|
| インストーラブルトリガー数 | 1ユーザー・1スクリプト当たり20個 | 1ユーザー・1スクリプト当たり20個 |
| トリガーの合計実行時間 | 1ユーザー当たり90分/日 | 1ユーザー当たり6時間/日 |
| 1回の通常スクリプト実行時間 | 6分 | 6分 |
| 同時実行数 | 1ユーザー当たり30 | 1ユーザー当たり30 |
シンプルトリガーには、これとは別に1回30秒の実行時間制限があります。
上限の単位に注目してください。「20個」はプロジェクト全体で一律20個ではなく、1ユーザー・1スクリプト当たりの値です。また、トリガーの合計実行時間は1回の長さではなく、1日に自動実行された時間の合計です。
まとめ
この記事では、GAS版のHello Worldとして、スプレッドシートの編集をきっかけにデータを読み書きする方法を試しました。
重要なポイントは次のとおりです。
- コンテナバインドGASは、ひも付いたスプレッドシートを簡単に操作できる
onEdit(e)を書くだけで、セル編集に反応するシンプルトリガーを利用できる- シンプルトリガーは自分のファイルを変更できるが、認可が必要な別ファイルにはアクセスできない
- 別スプレッドシートへ連携する場合は、インストーラブルトリガーを利用する
- インストーラブルトリガーは、トリガーを作成したユーザーの権限で動く
- トリガー数は1ユーザー・1スクリプト当たり20個で、日ごとの合計実行時間にも上限がある
最初は「A列を読んでB列へ書く」だけでも十分です。 最初の1歩としてぜひ試してみてください。
参考
- Google for Developers:Container-bound Scripts
- Google for Developers:Simple Triggers
- Google for Developers:Installable Triggers
- Google for Developers:Event Objects
- Google for Developers:Quotas for Google Services
- Google for Developers:SpreadsheetApp
※ 本記事の仕様と上限値は、2026年8月時点のGoogle公式情報を基に確認しています。
この記事をシェアする
合同会社raisexでは一緒に働く仲間を募集中です。
ご興味のある方は以下の採用情報をご確認ください。












