【要検証】Google Workspaceユーザー作成シート(Google Apps Script)

Google Workspaceのユーザー作成の際に、スプレッドシートのボタンを押して、ユーザーが作れたら便利と考えて、ChatGPTと相談しながら、Google Apps Scriptを作ってみました。
ただし、個人契約の試用期間テナントでの動作検証しか行っていないため、検証可能環境で検証後、使用するようにしてください。

機能概要

  • チェックをした行のユーザーをボタンを押せば、氏名、アドレス、パスワード組織部門を指定して作成できる

  • 作成前にメッセージボックスで確認され、作成後に管理画面で確認するリンクを自動で開く

  • 指定したグループにボタンを押せば追加できる。追加後に管理ログイベント検索画面リンクを自動で開く

  • 2段階認証強制化した組織のユーザーの場合に初回ログインに使えるように、バックアップコードを生成できる

ユーザー作成確認
グループ追加確認

使い方

  • こちらのシートをドライブにコピーして開く

  • シートのドメインや、パスワード、グループアドレス、組織を設定

  • 拡張機能→Apps Scriptを開き一度実行し権限を承認

  • その他

    • 初期パスワードには3文字だけランダムっぽくなる関数を入れてあるので、好きな初期パスワードに変更を

    • 組織はスラッシュ区切りのorgUnitPath(例:/管理本部/総務)を記入

    • G~J列は、雇用形態や、メモなど入れられるように空欄

    • 以下のようなサイトのコードと組み合わせて、グループや、組織の情報を他のシートに入れておくと便利


Google Apps Scriptコード

ユーザー作成

function createUserFromSheet() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ユーザーリスト");
  const lastRow = sheet.getLastRow();
  const range = sheet.getRange("A4:A" + lastRow);
  const checkboxes = range.getValues();
  const checkedRowsIndexes = [];

  // チェックされた行のインデックスを取得
  for (let i = 0; i < checkboxes.length; i++) {
    if (checkboxes[i][0] === true) {
      checkedRowsIndexes.push(i + 4); // インデックスは0から始まるため+2
    }
  }

  // 複数の行が選択されているか確認
  if (checkedRowsIndexes.length > 1) {
    Browser.msgBox("複数の行が選択されています。1行だけ選択してください。", Browser.Buttons.OK);
    return;
  } else if (checkedRowsIndexes.length === 0) {
    Browser.msgBox("ユーザーを作成する行が選択されていません。", Browser.Buttons.OK);
    return;
  }

  const rowIndex = checkedRowsIndexes[0];
  const lastName = sheet.getRange("B" + rowIndex).getValue();
  const firstName = sheet.getRange("C" + rowIndex).getValue();
  const email = sheet.getRange("D" + rowIndex).getValue();
  const password = sheet.getRange("E" + rowIndex).getValue();
  const orgUnitPath = sheet.getRange("K" + rowIndex).getValue();

  const confirmation = Browser.msgBox(
    "以下の情報でユーザーを作成しますか?\\n\\n" +
    "名: " + firstName + "\\n" +
    "姓: " + lastName + "\\n" +
    "メールアドレス: " + email + "\\n" +
    "組織: " + orgUnitPath + "\\n\\n" +
    "OK をクリックするとユーザーが作成されます。",
    Browser.Buttons.OK_CANCEL
  );

  if (confirmation == "ok") {
    const user = {
      primaryEmail: email,
      name: {
        givenName: firstName,
        familyName: lastName,
        fullName: firstName + ' ' + lastName,
      },
      orgUnitPath: orgUnitPath,
      password: password,
      changePasswordAtNextLogin: true,
    };

    // ユーザー作成リクエストを送信
    try {
      const createdUser = AdminDirectory.Users.insert(user);
      Browser.msgBox("ユーザーが作成されました。管理画面で確認してください。", Browser.Buttons.OK);

      // ユーザーを検索するページを開く
      const searchURL = 'https://admin.google.com/ac/search?query=' + encodeURIComponent(createdUser.primaryEmail) + '&tab=ALL';
      const html = "<script>window.open('" + searchURL + "');</script>";
      const userInterface = HtmlService.createHtmlOutput(html);
      SpreadsheetApp.getUi().showModalDialog(userInterface, "ユーザー検索画面に遷移");
    } catch (e) {
      Browser.msgBox("ユーザーの作成中にエラーが発生しました。\n詳細: " + e, Browser.Buttons.OK);
      Logger.log('ユーザーの作成中にエラーが発生しました: ' + e);
    }
  } else {
    Browser.msgBox("ユーザー作成をキャンセルしました。", Browser.Buttons.OK);
    Logger.log('ユーザー作成がユーザーによってキャンセルされました。');
  }
}

ネット上で、orgUnitPathのパラメーターを使ってユーザー作成をする情報があまり見つからず、気づくのに時間がかかりました。

グループメンバー追加


function addGroupMember() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('ユーザーリスト');
  const lastRow = sheet.getLastRow();
  try {
    // ユーザー情報を取得
    const dataRange = sheet.getRange("A4:R" + lastRow);
    const values = dataRange.getValues();
    for (let i = 1; i < values.length; i++) {
      if (values[i][0] === true) { // チェックボックスがチェックされている行のみ処理する
        const userEmail = values[i][3]; // D列のユーザーのメールアドレス
        let groupEmails = values[i].slice(11, 18); // L列からR列までのグループのメールアドレスを取得

        // 空欄のグループメールアドレスを無視して処理
        groupEmails = groupEmails.filter(function(email) {
          return email.trim() !== '';
        });

        // ユーザー名とグループを表示
        const userConfirmation = Browser.msgBox(
          "ユーザー: " + userEmail + "\\n" +
          "グループ: " + groupEmails.join(", ") + "\\n\\n" +
          "OK をクリックするとユーザーがグループに追加されます。",
          Browser.Buttons.OK_CANCEL
        );

        // OKが押された場合のみユーザーをグループに追加
        if (userConfirmation == "ok") {
          // グループごとにユーザーを追加
          for (let j = 0; j < groupEmails.length; j++) {
            const groupEmail = groupEmails[j];
            const member = {
              email: userEmail,
              role: 'MEMBER'
            };
            try {
              AdminDirectory.Members.insert(member, groupEmail);
              Logger.log('User %s added as a member of group %s.', userEmail, groupEmail);
            } catch (err) {
              // エラーメッセージを表示
              Browser.msgBox("エラー: " + err.message);
            }
          }
          Browser.msgBox("ユーザー " + userEmail + " をグループ " + groupEmails.join(", ") + " に追加実行。管理ログイベントを検索して確認してください。");
          // 指定されたURLを開く
          const investigationURL = 'https://admin.google.com/ac/sc/investigation?link=CgQIFRgB&ref=reporting';
          const html = "<script>window.open('" + investigationURL + "');</script>";
          const userInterface = HtmlService.createHtmlOutput(html);
          SpreadsheetApp.getUi().showModalDialog(userInterface, "監査ログ確認");
        } else {
          throw new Error("ユーザーの追加がキャンセルされました。");
        }
      }
    }
  } catch (err) {
    // エラーログを出力
    console.error(err);
    // エラーメッセージを表示
    Browser.msgBox("エラー: " + err.message);
  }
}

バックアップコード生成

Google Workspace2段階認証を強制した組織で、「新しいユーザーの登録期間」を指定するのが一般的な対応とされているようですが、登録期間中にユーザーに設定してもらえず個別対応することありませんか?
しかもその間は2段階認証なしでログインできるので、セキュリティにもよろしくなく。
2段階認証を強制した組織だと、管理画面でユーザーのバックアップコードを発行可能なので、初回ログイン情報と一緒にユーザーに渡すといいと考えて、この機能を付けました。

function generateBackupCodes() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ユーザーリスト");
  const lastRow = sheet.getLastRow();
  const range = sheet.getRange("A4:A" + lastRow);
  const checkboxes = range.getValues();
  const checkedRowsIndexes = [];

  // チェックされた行のインデックスを取得
  for (let i = 0; i < checkboxes.length; i++) {
    if (checkboxes[i][0] === true) {
      checkedRowsIndexes.push(i + 4); // インデックスは0から始まるため+2
    }
  }

  // 複数の行が選択されているか確認
  if (checkedRowsIndexes.length !== 1) {
    Browser.msgBox("1行だけ選択してください。", Browser.Buttons.OK);
    return;
  }

  const rowIndex = checkedRowsIndexes[0];
  const email = sheet.getRange("D" + rowIndex).getValue();
  
  try {
    AdminDirectory.VerificationCodes.generate(email);
  } catch (error) {
    Browser.msgBox("エラーが発生しました:" + error.message, Browser.Buttons.OK);
    return;
  }

  const verificationCodes = AdminDirectory.VerificationCodes.list(email).items;
  
  if (!verificationCodes || verificationCodes.length < 3) {
    Browser.msgBox("バックアップコードが見つかりません。", Browser.Buttons.OK);
    return;
  }

  const backupCodes = verificationCodes.slice(0, 3).map(item => item.verificationCode).join(", ");
  
  sheet.getRange("F" + rowIndex).setValue(backupCodes);
}


この記事が気に入ったらサポートをしてみませんか?