見出し画像

GraphAPIでEntraIDのユーザーを作成する&ユーザー情報を更新する

EntraIDの全ユーザーの情報を一括で更新したかったので、GraphAPIでやってみました。ついでにユーザーの新規作成もやってみました。



ユーザーを一括更新したい

少し前にそこそこ大規模な組織変更があり、EntraIDのほとんどのユーザーの部署情報を変更する必要が出てきました。CSVアップロードなどの方法でGUIから対応できないかなと思ったのですが、対応できず。

調べてみると、GraphAPIを使えばユーザー情報の一括更新が可能らしいので試してみることにしました。

また、これまでユーザーの新規作成を行うときはスプレッドシートに作成してあるテンプレに情報入力→CSVで落としてEntraIDにアップロードという方法で行なっていたのですが、せっかくなのでそれもGraphAPIで作成するスタイルに変えてみることにします。


GraphAPIを使うための準備

GraphAPIを利用するための準備に関しては、下記を参照させていただきました。APIのアクセス許可では「User.ReadWrite.All」を付与しておきます。


スプレッドシート+GASで実装する

なんでもガスガスすることからそろそろ抜け出したいなと思いつつ、一時的なDBを参照して何らかの処理をしたい場合、結局スプレッドシートから読み取ってGASで処理するというのが手っ取り早いのでGASで実装します。


ユーザーの新規登録

スプレッドシートには、登録したい情報のカラムを準備します。1行目に下記ヘッダをA列から順に記入していきます。

  • displayName

  • userPrincipalName

  • mailNickname

  • passwordProfile

  • accountEnabled

  • givenName

  • surname

  • jobTitle

  • department

  • usageLocation


続いてコード。ChatGPTに全部書いてもらいました。認証情報は全てスクリプトプロパティから参照し、シート名で取り込み元を指定しています。

// スプレッドシートを元にEntraIDにユーザーを新規作成する
function createUser() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('EntraID_user_add');
  const data = sheet.getDataRange().getValues();
  const headers = data[0];
  const users = data.slice(1);

  users.forEach(user => {
    let userDetails = {};
    headers.forEach((header, i) => {
      userDetails[header] = user[i];
    });

    // Convert "はい" to true and "いいえ" to false for accountEnabled
    userDetails.accountEnabled = userDetails.accountEnabled === 'はい';

    createAzureADUser(userDetails);
  });
}

function createAzureADUser(userDetails) {
  const tenantId = PropertiesService.getScriptProperties().getProperty("TENANT_ID");
  const clientId = PropertiesService.getScriptProperties().getProperty("CLIENT_ID");
  const clientSecret = PropertiesService.getScriptProperties().getProperty("CLIENT_SECRET");
  const resource = '<https://graph.microsoft.com>';
  const grantType = 'client_credentials';
  const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;

  // Get access token
  const tokenResponse = UrlFetchApp.fetch(tokenEndpoint, {
    method: 'post',
    payload: {
      client_id: clientId,
      client_secret: clientSecret,
      scope: resource + '/.default',
      grant_type: grantType
    }
  });

  const token = JSON.parse(tokenResponse.getContentText()).access_token;

  const url = '<https://graph.microsoft.com/v1.0/users>';
  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + token
    },
    payload: JSON.stringify({
      accountEnabled: userDetails.accountEnabled,
      displayName: userDetails.displayName,
      mailNickname: userDetails.mailNickname,
      userPrincipalName: userDetails.userPrincipalName,
      passwordProfile: {
        forceChangePasswordNextSignIn: true,
        password: userDetails.passwordProfile
      },
      givenName: userDetails.givenName,
      surname: userDetails.surname,
      jobTitle: userDetails.jobTitle,
      department: userDetails.department,
      usageLocation: userDetails.usageLocation
    })
  };

  const response = UrlFetchApp.fetch(url, options);
  Logger.log(response.getContentText());
}

accountEnabledは「はい」、usageLocationは「JP」で基本固定です。スプレッドシートの各列に情報を入力し実行すると、EntraIDに指定通りにユーザーが作成されます。

なお、このコードでは空欄があるとエラーになるので、適宜スキップする処理などを追加する必要があります。


ユーザー情報を更新する

ユーザー登録は簡単でした。次は本題のユーザー情報の更新を試します。既存ユーザーの部署の情報を変えたい旨をChatGPTに伝えて下記コードを作成してもらいました。

// 既存ユーザーの部署を変更する
function updateUserDepartment() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('EntraID_user_update');
  const data = sheet.getDataRange().getValues();
  const headers = data[0];
  const users = data.slice(1);

  users.forEach(user => {
    let userDetails = {};
    headers.forEach((header, i) => {
      userDetails[header] = user[i];
    });

    updateAzureADUserDepartment(userDetails);
  });
}

function updateAzureADUserDepartment(userDetails) {
  const tenantId = PropertiesService.getScriptProperties().getProperty("TENANT_ID");
  const clientId = PropertiesService.getScriptProperties().getProperty("CLIENT_ID");
  const clientSecret = PropertiesService.getScriptProperties().getProperty("CLIENT_SECRET");
  const resource = '<https://graph.microsoft.com>';
  const grantType = 'client_credentials';
  const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;

  // Get access token
  const tokenResponse = UrlFetchApp.fetch(tokenEndpoint, {
    method: 'post',
    payload: {
      client_id: clientId,
      client_secret: clientSecret,
      scope: resource + '/.default',
      grant_type: grantType
    }
  });

  const token = JSON.parse(tokenResponse.getContentText()).access_token;

  const url = `https://graph.microsoft.com/v1.0/users/${userDetails.userPrincipalName}`;
  const options = {
    method: 'patch',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + token
    },
    payload: JSON.stringify({
      department: userDetails.department
    })
  };

  const response = UrlFetchApp.fetch(url, options);
  Logger.log(response.getContentText());
}

A列に更新をかけたいユーザーのUPN、B列に変更後の部署名を記入して実行するだけです。実行が完了するとEntraID上で部署が変わっているのが確認できました。複数ユーザーを一括処理することも可能です。


今回は部署を変えるだけの仕様としましたが、一通りのカラムを用意しておいて入力のある箇所だけ更新する仕様にしたほうが実用性はありそうです。

あとChatGPTがかなり有能ですね。やりたいことやロジックだけ考えて伝えれば、もうほんとにコードを書かなくて良くなりました。

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