#はじめに
多くの情報システム管理者が頭を抱える事の1つにメーリングリスト(以下ML)の管理があります。
うちの会社では**G Suite(法人向けGoogleApps)**を利用しているのですが、長年問題を抱えていたMLの管理について、少しのルールと簡単なGASのコードで大分マシになりましたので、共有させていただきます。
#会社のメーリングリスト多すぎ問題
会社にはおびただしい数のMLが存在します。初めてに数えたときは2000個近くありました。
働いているメンバーは自分がどれだけのMLに参加しているかなんて普通は考えません。
しかし、誰かがその管理を行う必要があり、整理されているべきです。
日々、整理を行うにあたって、下記の項目が整理されていないと一気に管理が面倒になります。
- 何を目的に作成されたのか?(何のPJなのか?)
- 管理者は誰なのか?
- メンバーは誰なのか?
- 現在使われてるのか?
幸い、GSuiteはMLとして使用するグループには名前やメモを入れる事ができるので、目的や担当者を登録できます。
せっかくの年末の棚卸し期なので、一覧化して必要でないものはガンガン削っていきましょう。
#スプレッドシートの用意
MLのメアド、MLの説明、ML名、メンバー数、メンバーのメアドを一覧化したいと思います。
スプレッドシートのスクリプトエディタからGASのコードを入力していきます。
####トークンとトリガー
このコードでキモとなるのが、トークンとトリガーの関係です。
2000件近くのML、1件につき、5人のメンバーが登録されていた場合、10000件近く処理することになります(実際はもっと多いですが)。
GASの仕様で、処理が6分を超えるとタイムアウトエラーが起こります。
なので、処理ごとにプロセストークンを発行し、4分を超えた場合に現在のプロセスを再開するトリガーを発行する必要があります。
####コードに関する注意点
情シス向けに作成しております。管理者権限が無いと動作しない部分があります。
/**
* 全MLとユーザ一覧を取得
*/
function getGroupAddressAndUsers()
{
// アクティブなシートを設定
var ss = SpreadsheetApp.openById("ここにシートのIDを入力");
var sheet = ss.getSheets()[0];
var pageToken, prev_pageToken;
//スクリプト情報を取得
var Properties = PropertiesService.getScriptProperties();
//現在のページトークンを取得。無かったら初期化
var pageToken = Properties.getProperty("task_page");
if(pageToken == 'undefined') {
pageToken = null;
}
var rows = [];
var starttime = new Date(); //時刻格納用の変数
//タイトルを設定
sheet.getRange(1, 1, 1, 5).setValues([["メールアドレス", "説明", "名前", "メンバー数", "メンバーのアドレス"]]);
do {
//現在時刻と開始時刻の差分を取得
var nowtime = new Date();
var nowdiff = parseInt((nowtime.getTime()-starttime.getTime())/60000);
// ”Admin Directory API”からグループ一覧を取得
all_groups_page = AdminDirectory.Groups.list({
domain: 'gaiax.com', //使用しているドメイン
maxResults: 20, //取得する件数
pageToken: pageToken //トークン
});
var groups = all_groups_page.groups;
//取得するグループが無い場合は終了
if (!groups) {
return;
}
// グループに所属するメンバーの取得し、配列に保存
groups.forEach(function(group, i) {
var members = AdminDirectory.Members.list(group.email).members;
rows = addMemberRow(rows, group, members);
})
//現在時刻と開始時刻を比較して、差分が4分を超えていたら処理中断
//(5分を超える処理はタイムアウトエラーになるため)
if(nowdiff >= 4){
// 配列の内容をシートへ書き込み
sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 5).setValues(rows);
rows = [];
//次の処理のトリガーを設置、プロパティに現在のトークンを登録しプログラムを停止
Properties.setProperty("task_page",pageToken);
setTrigger();
return;
}
//新しいトークンを取得
prev_pageToken = pageToken;
pageToken = all_groups_page.nextPageToken;
} while (pageToken);
//トークンに変化がない場合、完了
if(prev_pageToken == pageToken) {
//プロジェクトトリガーを全削除
deleteTrigger();
//トリガー用変数の初期化
Properties.setProperty("task_page",'');
// シートに書き込み
sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 5).setValues(rows);
//5分を超えずに終わった場合
} else {
// シートに書き込み
sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 5).setValues(rows);
rows = [];
//次の処理のトリガーを設置,プロパティにトークンを登録しプログラムを停止
Properties.setProperty("task_page",pageToken);
setTrigger();
}
return;
}
//メンバーの配列データを返す
function addMemberRow(rows, group, members) {
// グループに所属するメンバーの取得
var nowtime = new Date();//////////////////////
//メンバーが居なかった場合
if(members == undefined || members == 0){
var cols = [];
cols.push(group.email);
cols.push(group.description);
cols.push(group.name);
cols.push(group.directMembersCount);
cols.push("-----");
cols.push(nowtime.toLocaleString());
rows.push(cols);
//メンバーが居た場合
} else {
for (var j = 0; j < members.length; j++){
var cols = [];
cols.push(group.email);
cols.push(group.description);
cols.push(group.name);
cols.push(group.directMembersCount);
cols.push(members[j].email);
rows.push(cols);
cols.push(nowtime.toLocaleString());
}
}
return rows;
}
//トリガーを全削除する関数
function deleteTrigger() {
var allTriggers = ScriptApp.getProjectTriggers();
for(var i=0; i < allTriggers.length; i++) {
ScriptApp.deleteTrigger(allTriggers[i]);
}
}
//トリガーを設置する関数(getGroupAddressAndUsers 関数を実行予定として登録)
function setTrigger(){
deleteTrigger();
var triggerman = ScriptApp.newTrigger("getGroupAddressAndUsers")
.timeBased()
.everyMinutes(5)
.create();
}
//トリガーをリセット
function resetTrigger() {
var Properties = PropertiesService.getScriptProperties();
//プロジェクトトリガーを全削除
deleteTrigger();
//トリガー用変数の初期化
Properties.setProperty("task_page",'');
}