3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Looker Studioで作るMDMダッシュボード Microsoft IntuneとJamf Proのデータをまとめて分析する方法

Posted at

はじめに

情報システム部門(以下、情シス)の仕事は、コストセンターと見られることが多く、何も価値を生み出さないと思われがちですが、決してそうではありません。

日々の業務から課題を発見し、適切な課題設定及び施策を実行することで、資産管理やセキュリティの観点でバリューを提供することは可能です。

本記事は「身の回りの困りごとを楽しく解決! by Works Human Intelligence Advent Calendar 2025」に沿って、情シスの悩みになりがちなデバイス管理の課題を解決するためのヒントについて記載しています。

デバイス管理に関する製品は、Microsoft Intune及びJamf Proを使用しています。

デバイス管理の課題

情シスのデバイス管理に関する業務は、組織の規模によって大きく異なります。

例えば、スタートアップや中小企業など従業員が少ない組織の場合、インフラを専門とする担当者が手動でキッティングを行うことが多いと思います。

従業員が100人を超えてくる組織になると、手動のキッティングでは厳しくなるため、MDM製品を導入してデバイス管理を行うことが多いのではないでしょうか。

しかし、MDM製品を用いてデバイス管理を行っているものの資産管理はエクセルやスプレッドシートで別途台帳を作成しているケースが多くあります。こうした二重管理により、MDMに登録されているデータとPC管理台帳との不整合が発生し、結果として以下のような課題が発生します。

  • PC管理台帳の更新漏れによって、デバイスの利用状況が不明
  • PC管理台帳に記載はないが、MDMに登録があるデバイス
  • PC管理台帳に記載はあるもものの、MDMに登録がないデバイス
  • 知らないうちにBYODとしてMDMに登録されたデバイス
  • セキュリティ製品の導入有無が不明なデバイス
  • OSのサポート切れが発生しているのに使用され続けているデバイス
  • MDMプロファイルの期限切れ
  • デバイスを支給しているのにも関わらず、実際は使用されていないデバイス

このような課題は、セキュリティ的にも顕在化された問題に発展する可能性があります。

animal_chara_computer_azarashi.png

MDMダッシュボード

上記に挙げたような課題を解決するためには、問題のあるデバイスを特定して、利用者に通知を行うなどの運用が発生します。

MDMのソリューションを用いて問題のあるデバイスを特定するためには、基本的に管理画面からデバイスを検索するなどの操作を行う必要があるため、インタラクティブな操作が多く、日々繰り返し行うには、煩雑な作業になりがちです。

そこで、MDMダッシュボードを整備して、情報の利活用を行うことで、問題のあるデバイスを早期に検出することが可能になります。

本記事では、以下のツールを組み合わせてMDMダッシュボードを実現しています。

  • MDM製品で用意されているAPI
  • Google スプレッドシート
  • Google Apps Script
  • Looker Studio

MDMダッシュボード.png

Microsoft Intune

Microsoft Intune(以下、Intune)は、Microsoftが提供しているクラウドベースのデバイス管理ソリューションです。

Mobile Device Management(MDM)及びMobile Application Management(MAM)の機能を使用して、組織が所有するデバイスやユーザーが所有する個人デバイスのアクセスとデータを保護することができます。

Intuneで管理してるデバイスの情報を取得するためには、Microsoft Graphで用意されているAPIを利用します。

Microsoft Graph APIを利用するには、認可やトークン発行を行うためにEntra IDで「アプリの登録」が必要です。

Entra IDで行う「アプリの登録」とは、Entra IDにアプリケーションを登録することを意味しますが、登録するのはアプリケーションオブジェクトとして、アプリケーションのテンプレートに該当します。

エンタープライズアプリケーション」については、テナント内でアプリケーションを実際に利用するためのインスタンスです。

インスタンスとして登録されるのは「サービスプリンシパルオブジェクト」と呼ばれ、アプリケーションオブジェクトから作成されたテナント固有のインスタンスを意味します。

「アプリの登録」で新しいアプリを作成すると、そのテナント内に対応するエンタープライズアプリケーション(サービスプリンシパル)が自動で作成されます。

アプリケーションに関する詳細については、公式ドキュメントの「Microsoft Entra ID のアプリケーションとサービス プリンシパル オブジェクト」をご参照ください。

アプリの登録

アプリの登録手順の例を以下に記載します。

Entra IDを開き、左ペインのナビゲーションより「アプリの登録」を選択します。

スクリーンショット 2025-11-27 20.52.49.png

「新規登録」を押します。

スクリーンショット 2025-11-27 20.53.07.png

「名前」にアプリケーションの名前を入力して「登録」を押します。

スクリーンショット 2025-11-27 20.55.13.png

アプリが作成されます。

スクリーンショット 2025-11-27 20.55.31.png

「証明書とシークレット」を選択します。

スクリーンショット 2025-11-27 20.55.44.png

「新しいクライアントシークレット」を押すと、右ペインに「クライアントシークレットの追加」が表示されるので「有効期間」を確認して「追加」を押します。

スクリーンショット 2025-11-27 20.56.10.png

クライアントシークレットが作成されるので、値を確認します。※値は作成後しか表示されません

スクリーンショット 2025-11-27 20.56.25.png

次に「APIのアクセス許可」を選択します。

スクリーンショット 2025-11-27 20.56.40.png

「アクセス許可の追加」を押すと、右ペインに「APIアクセス許可の要求」が表示されるので「Microsoft Graph」を選択します。

スクリーンショット 2025-11-27 20.56.49.png

「アプリケーションの許可」を選択します。

スクリーンショット 2025-11-27 20.56.56.png

「アクセス許可を選択する」の検索ボックスにDeviceManagementManagedDevices.Read.Allを入力して、チェックボックスにチェックを入力後「アクセス許可の追加」を押します。

スクリーンショット 2025-11-27 20.58.24.png

他のアクセス権も追加したい場合は、同様の操作を行います。例えば、ライセンスに関する情報を取得したい場合はLicenseAssignment.Read.Allを入力します。

スクリーンショット 2025-11-27 20.58.50.png

管理者の同意が許可されると、アクセス許可が与えられます。

Microsoft Graph API

Microsoft Graph APIは、単一のエンドポイントとしてhttps://graph.microsoft.comを提供しています。

REST APIやSDKを使用して、エンドポイントにアクセスを行うことで、Microsoft 365、Windows、Enterprise Mobility + Securityなどに関するデータを取得することができます。

本記事では、GASで実装するにあたり、以下の情報を取得するためのサンプルコードを記載しています。

  • デバイスの一覧
  • デバイスにインストールされているアプリケーション

はじめにMicrosoft Graph APIを利用するには、トークンを取得する必要があります。また、トークンを取得するためには、Entra IDで作成したアプリケーションに関するclient_id及びclient_secretの認証情報が必要です。

以下の例では、プロパティサービスにclient_id及びclient_secretの認証情報を設定して、トークンの取得を行なっています。

  • トークンの取得
// プロパティサービスのインスタンス
const SCRIPT_PROPS = PropertiesService.getScriptProperties();

// プロパティサービスの設定
const CLIENT_ID = SCRIPT_PROPS.getProperty('CLIENT_ID');
const CLIENT_SECRET = SCRIPT_PROPS.getProperty('CLIENT_SECRET');
const TARGET_FOLDER_ID = SCRIPT_PROPS.getProperty('TARGET_FOLDER_ID');

const TOKEN_URL = "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token";

/**
 * OAuth 2.0 トークンを取得
 */
function getAccessToken() {
  const tokenUrl = TOKEN_URL;

  const payload = {
    grant_type: "client_credentials",
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    scope: "https://graph.microsoft.com/.default",
  };

  const options = {
    method: "post",
    payload: payload
  };

  const response = UrlFetchApp.fetch(tokenUrl, options);
  const json = JSON.parse(response.getContentText());

  return json.access_token;

上記で取得したトークンを利用して、他のエンドポイントのAPIにアクセスを行うことができます。以下は、デバイスの一覧を取得するためのコードです。

  • デバイスの一覧
const DEVICES_MANAGEMENT_URL = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices";

/**
 * managedDevices
 */
function getManagedDevices(token) {
  const url = DEVICES_MANAGEMENT_URL;

  const options = {
    method: "get",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Accept": "application/json"
    }
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const json = JSON.parse(response.getContentText());

    Logger.log(`Managed Devices Count: ${json["@odata.count"]}`);

    return {
      results: json.value || []
    };

  } catch (e) {
    Logger.log("APIリクエストエラー: " + e.message);
    return { results: [] };
  }
}

デバイスにインストールされているアプリケーションについては、beta版ですが、以下のエンドポイントが用意されています。

  • デバイスにインストールされているアプリケーション
const DETECTEDAPPS_URL = "https://graph.microsoft.com/beta/deviceManagement/managedDevices";

/**
 * detectedApps
 */
function getDetectedAppss(token, id) {
  const url = `${DETECTEDAPPS_URL}/${id}/detectedApps`;

  const options = {
    method: "get",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Accept": "application/json"
    }
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const json = JSON.parse(response.getContentText());

    Logger.log(`detectedApps Count: ${json["@odata.count"]}`);
    Logger.log(json["value"]);

    return {
      results: json.value || []
    };

  } catch (e) {
    Logger.log("APIリクエストエラー: " + e.message);
    return { results: [] };
  }
}

detectedAppsのエンドポイントの情報を取得するためには、デバイス毎のidが必要になるため、デバイスの一覧で取得したidを利用します。

Jamf Pro

Jamf Pro(以下、Jamf)は、Apple製品の一元管理を行うことができるソリューションです。

基本的にはIntuneと同じような考え方に基づき、ポリシーや構成プロファイルを作成して、デバイスの一元管理を行いますが、JamfではMDMプロファイルの運用が伴ないます。

Jamfで利用できるAPIは、Classic APIと、Jamf Pro APIの2種類が存在します。

基本的には、Jamf Pro APIが現在提供しているスタンダードなAPIになるため、Jamf Pro APIの利用を推奨します。

また、Jamf Pro APIを使用する場合は、Intuneと同じように認可やトークン発行が必要になるため、APIクライアントを作成します。

APIクライアント

左ペインのナビゲーションより「設定」から「システム」タブを開き、「APIロールとクライアント」を選択します。

スクリーンショット 2025-11-28 21.03.03.png

「APIロール」のタブより「新規」を押します。

スクリーンショット 2025-11-28 20.53.24.png

「表示名」を入力して「権限」にRead Computersと、Read Advanced Computer Searchesを選択して「保存」を押します。

スクリーンショット 2025-11-28 20.59.36.png

次に「APIクライアント」のタブより「新規」を押します。

スクリーンショット 2025-11-28 20.59.58.png

「表示名」を入力してAPIロールに先ほど作成したロールを選択して「保存」を押します。

スクリーンショット 2025-11-28 21.00.19.png

クライアントシークレットが作成されるので、値を確認します。※値は作成後しか表示されません

スクリーンショット 2025-11-28 21.45.44.png

Jamf Pro API

Jamf Pro APIを用いてデバイスのインベントリ検索を行う場合は、computer-inventoryのAPIを利用します。

エンドポイントのURLとしてv2/computers-inventoryが用意されていて、一般やOSなどのセクションを指定して、情報を取得することができます。指定がない場合は、デフォルトでGENERALセクションのデータが返されます。

本記事では、GENERALOPERATING_SYSTEMAPPLICATIONSのセクションを利用しています。

はじめにJamf Pro APIを利用するには、トークンを取得する必要があります。また、トークンを取得するためには、作成したAPIクライアントのclient_id及びclient_secretの認証情報が必要です。

以下の例では、プロパティサービスにclient_id及びclient_secretの認証情報を設定して、トークンの取得を行なっています。

// プロパティサービスのインスタンス
const SCRIPT_PROPS = PropertiesService.getScriptProperties();

// プロパティサービスの設定
const CLIENT_ID = SCRIPT_PROPS.getProperty('CLIENT_ID');
const CLIENT_SECRET = SCRIPT_PROPS.getProperty('CLIENT_SECRET');

// JAMF_PRO_URLはクライアント毎に異なります
const JAMF_URL = "https://JAMF_PRO_URL.jamfcloud.com";

/**
 * OAuth 2.0 トークンを取得
 */
function getAccessToken() {
  const tokenUrl = `${JAMF_URL}/api/oauth/token`;

  const payload = {
    grant_type: "client_credentials",
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
  };

  const options = {
    method: "post",
    payload: payload
  };

  const response = UrlFetchApp.fetch(tokenUrl, options);
  const json = JSON.parse(response.getContentText());

  return json.access_token;
}

上記で取得したトークンを利用して、他のエンドポイントのAPIにアクセスを行うことができます。以下は、インベントリ検索(GENERAL)行うためのコードです。

/**
 * インベントリ検索(GENERAL) - ページ単位
 */
function getInventorySearch_ComputerInventoryGeneral(token, page, pageSize) {
  const url = `${JAMF_URL}/api/v2/computers-inventory?section=GENERAL&page=${page}&page-size=${pageSize}&sort=general.name%3Aasc`;

  const options = {
    method: "get",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Accept": "application/json"
    }
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const json = JSON.parse(response.getContentText());

    Logger.log(`GENERAL Page=${page}, Results=${json.results.length}`);

    return {
      totalCount: json.totalCount || 0,
      results: json.results || []
    };

  } catch (e) {
    Logger.log("APIリクエストエラー: " + e.message);
    return { totalCount: 0, results: [] };
  }
}

インベントリ検索が返すレスポンスは、最大100件となります。そのため、totalCountを取得することで、ページ分ループ処理を行うことで、全件取得するようにしています。

インベントリ検索の画面で作成した検索条件は、Classic APIのadvancedcomputersearchesエンドポイントを利用することで実行できます。

例えば、MDMプロファイルが登録されていないデバイス、MDMプロファイルが有効期限切れのデバイスを取得するなどの応用が可能です。

/**
 * インベントリ検索(エンドポイントの末尾のNUMは、検索条件毎に異なる)
 */
function getInventorySearch_MDMProfileExpired(token) {
  const url = `${JAMF_URL}/JSSResource/advancedcomputersearches/id/${NUM}`;
  const options = {
    method: "get",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Accept": "application/json" 
    }
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const json = JSON.parse(response.getContentText());
    Logger.log("インベントリ検索:" + JSON.stringify(`${json.advanced_computer_search.id}:${json.advanced_computer_search.name}`));

    const computersArray = json.advanced_computer_search.computers;

    if (!Array.isArray(computersArray)) {
      Logger.log("APIレスポンスにcomputers配列が見つかりませんでした。");
      return [];
    }
  
    return computersArray.map(computer => ({
      name: computer.name, 
      udid: computer.udid,
      id: computer.id,
      Computer_Name: computer.Computer_Name,
      MDM_Profile_Expiration_Date: computer.MDM_Profile_Expiration_Date
    }));
  } catch (e) {
    Logger.log("APIリクエストエラー: " + e.message);
    return []; // エラー時は空の配列を返す
  }
}

Looker Studio

Looker Studioは、Googleの一般向けサービスをはじめ様々なデータを接続してダッシュボードやレポートとして共有できるデータ可視化のツールです。

基本的に無料で利用することができますが、Looker Studio Proにアップグレードすることで、チーム コンテンツ管理を含むサポートと拡張管理機能が利用できるようになります。

本記事では、Google スプレッドシートをデータソースとして利用し、PC管理台帳、Intune及びJamfの情報を可視化しています。

以下はサンプルのデータを基に作成したレポートのイメージですが、スコアカードや円グラフを用いてサマリ情報を表示したり、PC管理台帳とIntuneのデータを突合して、Intuneのチェックイン時間が6ヶ月以上前のデバイスをレポートに表示しています。

スクリーンショット 2025-12-01 23.39.36.png

このように長期間チェックインが行われていない怪しいデバイスを特定して、可視化することができます。

Jamfで管理しているMacのデバイスについても、MDMプロファイルの有効期限が切れたデバイスを表示することで、問題のあるデバイスを速やかに特定できます。

スクリーンショット 2025-12-05 23.53.25.png

デバイスのチェックインについて、IntuneはlastSyncDateTimeより確認できます。また、Jamfについては、lastContactTimeより確認できます。

おわりに

MDMダッシュボードは作って終わりではなく、継続的な運用が伴う課題解決のツールです。

日々の運用で見えてくる課題や、新たに求められる可視化要件を取り込みながら、より使いやすく、より確実に判断できるダッシュボードへ育てていきましょう。

本記事が、資産管理の効率化やセキュリティ強化の一助になれば幸いです。

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?