Google Apps ScriptでKintoneのユーザ一覧を取得する【GAS】

仕事で各種サービスの現在のライセンス割当状況を一括で集めるプログラムを作成中。KintoneもOAuth2.0認証が出来るので、それでらくらくユーザ一覧の情報が取得できるかと思いきや、以外な問題点にぶつかりちょっと沼ったので記録を残しておこうと思いました。

今回はkintoneというよりもCyboze共通APIを叩いて取得するタイプの処理となり、ちょっと変わった認証が必要です。

今回利用するスプレッドシート

事前準備と注意点

事前準備

kintoneのCyboze共通管理画面に於いて今回のAPIを叩くには以下の3つを満たす必要があります。

  1. 認証するユーザは共通管理者のロールが割り当てられてる必要があります。
  2. 認証するユーザには個別にログインパスワードを設定しておく必要があります。
  3. ユーザID:パスワードをBase64でエンコードした文字列を用意しておく必要があります。

この準備だけはしっかりしておきましょう。

注意点

今回のスクリプトですが、沼ったポイントが2つありました。

  1. Cyboze共通APIはOAuth2.0認証の処理で叩くことが出来ない
  2. ユーザのサービス取得のAPIではユーザ数が多いとドキュメントの仕様で書くとエラーとなる

1.の問題点、特に企業で使ってる場合遭遇するもので、自分もSAML認証でKintoneとGoogle Workspaceとを連携している為、ユーザは基本自動認証でログインされます。しかし、実際にはユーザID:パスワードをBase64でエンコードした文字列を、X-Cybozu-Authorizationで指定してリクエストをしないと、403エラー「CB_OA01 : cannot access protected resource」で全てエラーになります(このエラーコードの記載がドキュメントに無い)。

その為、認証するユーザアカウントにきちんと個別でパスワード設定を入れておかないと認証自体も通りません。

また、2.の問題点。ユーザ一覧のAPIには割当られてるライセンスの項目が無い為、サービス一覧APIで別途リクエストが必要なのですが、人数が多い場合、ドキュメントにあるように「codes[0]=hoge@test.com&codes[1]=tomato@test.com」と繋げすぎると、UrlfetchAppのURL長の制限に掛かってリクエストが出来ません。Limit Exceeded: URLFetch URL Lengthというエラーになります。(このオプションを省略するとデフォルトで100件取得になるのでオプションを付けないのが正解)。あとは、offsetでどこから何件とるか?を指定することで全員の情報が取得できるというややこしい仕組みになっています。

ソースコード

//トータルユーザ枠
var userlength = 300;

//ドメイン
var domain = "hoge";

//ユーザ一覧を取得する
function getKintoneUsers(){
  //uiを取得する
  let ui = SpreadsheetApp.getUi();

  //シートを取得する
  let prop = PropertiesService.getScriptProperties();
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getSheetByName("ライセンス管理");

  //サービス名を指定
  let servicename = "kintone";

  //書き込み用配列
  let array = [];
  let offset = 0;
  let loopman = Math.ceil(userlength / 100);

  //リクエストオプションを指定
  //認証ユーザにパスワード設定しておき、ユーザメアド:パスワードをBase64エンコードした値をヘッダに指定が必要
  //OAuth認証だとこのAPIは何故か実行できない
  let options = {
    method:"GET",
    headers: {
      "X-Cybozu-Authorization": "ユーザID:パスワードをbase64でエンコードした文字列",
    }
  }

  //ループでデータを取得する
  for(var i = 0; i<loopman; i++){
    //リクエストエンドポイントを指定
    var endpoint = "https://" + domain + ".cybozu.com//v1/users.json?offset=" + offset;

    //HTTPリクエスト
    var res = UrlFetchApp.fetch(endpoint,options);

    //ステータスコード
    let statuscode = res.getResponseCode();

    //レスポンスデータ
    var result = JSON.parse(res.getContentText());

    //ユーザ情報を格納する
    var users = result.users;

    for(var j = 0;j<users.length;j++){
      //レコードを一個取り出す
      let rec = users[j];

      //メールアドレスを取得する
      let str = rec.email;

      //書き込み用一時配列を用意
      let temparr = [
        rec.id,
        rec.name,
        str,
        servicename,
        "",
      ];

      //arrayに追加する
      array.push(temparr)
    }

    //offsetを更新する
    offset = offset + 100
  }

  //offsetを初期化
  offset = 0;

  //サービス一覧を取得する
  var array2 = [];
  for(var i = 0;i<loopman;i++){
    //リクエストエンドポイントを指定
    var endpoint = "https://" + domain + ".cybozu.com/v1/users/services.json?offset=" + offset;

    //HTTPリクエスト
    var res = UrlFetchApp.fetch(endpoint,options);

    //ステータスコード
    let statuscode = res.getResponseCode();

    //レスポンスデータ
    var result = JSON.parse(res.getContentText());

    //ユーザ情報を格納する
    var users = result.users;

    for(var j = 0;j<users.length;j++){
      //レコードを一個取り出す
      let rec = users[j];

      //メールアドレスを取得する
      let str = rec.code;

      //書き込み用一時配列を用意
      let temparr = [
        str,
        rec.services[0]
      ];

      //arrayに追加する
      array2.push(temparr)
    }

    //offsetを更新する
    offset = offset + 100;
  }

  //array2のデータをarrayに反映する(ライセンス割り当て状況)
  for(var i = 0;i<array.length;i++){
    //レコードを一個取り出す
    let rec = array[i];

    //array2側を探索
    for(var j = 0;j<array2.length;j++){
      if(rec[3] == array2[j][0]){
        rec[4] = array2[j][1];
        break;
      }
    }
  }

  //スプレッドシートの最終行を取得する
  license = ss.getSheetByName("ライセンス管理")
  let endrow =  Number(license.getLastRow()) + 1;

  //スプレッドシートに書き出しする
  let lastColumn = array[0].length;  //カラムの数を取得する
  let lastRow = array.length;      //行の数を取得する
  sheet.getRange(endrow,1,lastRow,lastColumn).setValues(array); 

  //終了
  ui.alert(servicename + "のユーザ一覧を出力しました。")

}
  • kintoneにユーザ登録されてる総合計人数をuserlengthに入れておきます(ライセンスの有無を問わず)
  • 各テナントのドメインをdomainに必ず入れておきましょう。
  • 総合計人数を100で割った数をループさせる回数として計算(1回に100名分しか取れない為)
  • リクエストヘッダはX-Cybozu-Authorizationで事前準備で作っておいたbase64の値を入れておきます。
  • まずはユーザを取得するAPIでユーザ情報をarrayに格納しておきます。この時次のループでは100足した数をoffsetに入れ直して次の100件を取得するようにします。
  • 次にユーザに割り当てられてるサービスを取得するAPIでサービス情報をarray2に格納しておきます。
  • array2のサービス情報をarray1に格納しておきます。ライセンスがある場合は値が入ってる筈
  • 最期に配列データを一括で書き出します。

関連リンク

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)