GASでスプレッドシートの範囲を保護して
編集ミスを防ぐ方法

数式やマスタデータを、複数人での運用中に誰かがうっかり書き換えてしまう——。そんな事故を、Protection(範囲・シートの保護を表すオブジェクト)を使ってコードで防ぐ方法を解説します。

|対象: GAS / スプレッドシート / 範囲保護

Table of Contents

なぜ範囲保護をコードで行うのか

スプレッドシートの保護は、メニューの「データ > シートと範囲を保護」から手作業でも設定できます。 ただ、シートやテンプレートを量産する運用では、毎回手で設定するのは手間ですし、設定漏れも起きます。 GAS(Google Apps Script)でコード化しておけば、テンプレート複製時に保護も自動でかけられます。

数式を守る

集計用の数式列を、値の上書きや行削除から守り、計算結果を壊さない

マスタを固定

商品マスタや単価表など、参照専用のデータを誤編集から保護する

役割で分ける

承認ステータスなど、特定の担当者だけが触れる列を明確にする

量産に強い

テンプレート複製時に保護も自動適用し、設定漏れをなくす

特定範囲を保護する基本コード

基本はrange.protect()で保護を作り、removeEditors()で編集者を外すだけです。編集者を外すと、保護の作成者(=スクリプト実行者)以外は編集できなくなります。

// A2:C10 の範囲を保護し、所有者以外は編集できないようにする
function protectRange() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("マスタ");
  const range = sheet.getRange("A2:C10");

  const protection = range.protect();
  protection.setDescription("マスタ範囲(編集禁止)");

  // 現在の編集者から自分以外を外す
  const me = Session.getEffectiveUser();
  protection.removeEditors(protection.getEditors());
  protection.addEditor(me);

  // シート全体が編集者に開放されている場合の保険
  if (protection.canDomainEdit()) {
    protection.setDomainEdit(false);
  }
}

setDescription()は保護に名前を付ける設定で、後から一覧で見分けるのに役立ちます。canDomainEdit()は「同じドメインの全員が編集できる状態か」を返すメソッドで、組織アカウントでの共有時の開放を閉じる保険として入れています。

警告だけ出すソフトな保護

完全に編集を止めるとかえって不便な列もあります。そんなときはsetWarningOnly(true)を使います。編集自体はできますが、触ろうとすると「本当に編集しますか?」という確認ダイアログが出るため、 うっかり編集の抑止になります。編集者を外す設定は不要です。

// 「本当に編集しますか?」の警告だけ出すソフト保護
function protectWithWarning() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("集計");
  const range = sheet.getRange("D2:D100"); // 数式が入った列など

  const protection = range.protect();
  protection.setDescription("数式列(警告のみ)");
  protection.setWarningOnly(true); // ブロックせず警告だけ
}

特定の人だけ編集を許可する

「承認ステータスは責任者だけが変えられるようにしたい」といった場合は、 いったん全員を外してから、許可したい人だけをaddEditors()で戻します。順番を「外す→戻す」にするのがポイントです。

// 特定の人だけ編集を許可する
function protectExceptEditors() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("承認");
  const range = sheet.getRange("E2:E100"); // 承認ステータス列

  const protection = range.protect();
  protection.setDescription("承認列(担当者のみ編集可)");

  // いったん全員を外してから、許可する人だけ戻す
  protection.removeEditors(protection.getEditors());
  protection.addEditors([
    "manager@example.com",
    "leader@example.com",
  ]);
}

シート全体を保護し入力欄だけ開ける

申請フォームのように「入力してほしいセルはごく一部で、それ以外は触ってほしくない」ケースでは、 シート全体をsheet.protect()で保護し、setUnprotectedRanges()で入力欄だけを保護から除外します。守る範囲を指定するより、開ける範囲を指定するほうが安全です。

// シート全体を保護しつつ、入力欄だけ編集可能にする
function protectSheetExceptInput() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("申請フォーム");

  const protection = sheet.protect();
  protection.setDescription("申請フォーム(入力欄以外は保護)");

  const me = Session.getEffectiveUser();
  protection.removeEditors(protection.getEditors());
  protection.addEditor(me);

  // B2:B10 だけは誰でも編集できるように除外する
  protection.setUnprotectedRanges([sheet.getRange("B2:B10")]);
}

保護をコードで解除・かけ直す

保護を更新したいときは、まず既存の保護をすべて解除してからかけ直すと、同じ範囲に保護が二重にかかるのを防げます。getProtections()ProtectionType(RANGE か SHEET)を渡して一覧を取得し、remove()で外します。自分が解除できる保護かどうかはcanEdit()で確認しておくと安全です。

// 既存の保護をすべて解除する(かけ直す前の初期化に便利)
function clearAllProtections() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("マスタ");

  const rangeProtections = sheet.getProtections(
    SpreadsheetApp.ProtectionType.RANGE
  );
  rangeProtections.forEach((p) => {
    if (p.canEdit()) p.remove();
  });

  const sheetProtections = sheet.getProtections(
    SpreadsheetApp.ProtectionType.SHEET
  );
  sheetProtections.forEach((p) => {
    if (p.canEdit()) p.remove();
  });
}

複数シートへ一括適用する

シート数が多いブックでは、getSheets()で全シートをループし、見出し行など共通の範囲をまとめて保護すると効率的です。 空のシートを飛ばすガードを入れておくとエラーになりにくくなります。

// 複数シートの見出し行(1行目)をまとめて保護する
function protectHeaderRows() {
  const ss = SpreadsheetApp.getActive();
  const me = Session.getEffectiveUser();

  ss.getSheets().forEach((sheet) => {
    if (sheet.getLastColumn() === 0) return; // 空シートはスキップ

    const headerRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
    const protection = headerRange.protect();
    protection.setDescription(sheet.getName() + " の見出し行");
    protection.removeEditors(protection.getEditors());
    protection.addEditor(me);
  });
}

実務での注意点

1. 保護はオーナーの操作をブロックしない

範囲保護はあくまで「他の編集者」を制限する仕組みです。スプレッドシートのオーナーや、保護に編集者として残っている人は編集できます。 GAS自身が値を書き込む処理は、実行者に編集権限があれば保護を無視して動く点も理解しておきましょう。

2. 実行アカウントの権限に依存する

他人を編集者から外す操作は、実行者がオーナーまたは十分な権限を持つ編集者でないと期待どおりに反映されないことがあります。 共有ドライブや組織のポリシーによっても挙動が変わるため、必ず実際の運用アカウントで動作確認をしてください。

3. 保護の数が増えすぎないよう管理する

かけ直しのたびに既存の保護を解除せず追加すると、同じ範囲に保護が積み重なって管理しづらくなります。 更新系の処理では「解除してから作り直す」を基本にし、setDescriptionで用途を明記しておくと運用が楽になります。

まとめ

GASの範囲保護は、range.protect()/sheet.protect()と編集者の付け外しを組み合わせるだけで、 数式やマスタを誤編集から守れます。完全にブロックしたいなら編集者を外す、うっかりだけ防ぎたいなら警告のみ、 一部だけ開けたいなら除外範囲、と使い分けるのがコツです。テンプレート複製や定期処理に組み込めば、設定漏れのない安全な運用ができます。

よくある質問

できます。range.protect()で範囲を保護するProtectionオブジェクトを取得し、removeEditors()で編集者を外すと、その範囲は所有者(と明示的に許可した人)以外は編集できなくなります。シート全体を保護したい場合はsheet.protect()を使います。

できます。protection.setWarningOnly(true)を使うと、編集自体はブロックせず「本当に編集しますか?」という警告ダイアログを出すソフトな保護になります。うっかり編集は防ぎたいが、必要なら本人の判断で編集させたい列に向いています。

protection.addEditor("user@example.com")で編集を許可するユーザーを個別に追加できます。addEditors()で複数人をまとめて追加することも可能です。まずremoveEditors()で全員を外してから、許可したい人だけをaddEditorで戻すのが安全です。

sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE)で範囲保護の一覧を取得し、それぞれにremove()を呼ぶと解除できます。ProtectionType.SHEETを指定すればシート保護を解除できます。保護をかけ直す前に一度すべて解除しておくと、二重に保護がかかるのを防げます。

スクリプトを実行するユーザーが、そのスプレッドシートの編集権限を持っている必要があります。他人を編集者から外す(removeEditors)操作は、実行者がオーナーまたは十分な権限を持つ編集者でないと反映されない場合があります。共有ドライブや組織のポリシーによっても挙動が変わるため、実際の運用アカウントでのテストが重要です。

GAS開発・業務Webシステムを
相談する。

範囲保護以外にも、入力規則・帳票出力・Gmail自動化など、複数人でも壊れにくいスプレッドシート運用の仕組みづくりをご相談いただけます。

GAS Webシステム開発を見る