スポンサーリンク

Kandjiのデバイス一覧を取得してみた

はじめに

こんにちは。スタートアップ企業で情シスをやってるヤスムラです。

今回は、Kandji MDMのAPIを使ってデバイス情報を取得するスクリプト(GAS)を作成したのでご紹介したいと思います。

Kandji API
# Welcome to the Kandji API Documentation You can find your API URL in Settings > Access. The API URL will follow the be...

GASを利用することによる属人化の問題はここでは触れませんが、Kandjiをこれから導入しようとしている方、すでに導入している方の参考になれば幸いです。

この記事はこんな方にオススメ

デバイス管理を行う情シスの方
すでにKandji MDMを利用している管理者の方
これからKandji MDMを導入検討している管理者の方

これを利用すれば、資産管理台帳の作成や最新化に役に立つと思います。
またSaaS管理サービスを利用して資産管理を行っている方は、現状Kandjiとのデバイス連携機能はないと思うので、手動同期させたい場合も有効な手段になると思います。

手順

手順は以下の通りです。

1.Kandji APIを作成

1. Kandjiにログイン
2. 左メニューにて[SETTINGS]>[Access]タブを開く
3. API Tokenにある[+Add API Token]をクリック


4. [Name]にわかりやすい名前を入力して[Create]をクリック


5. Tokenをコピーしてチェックをつけたら[Next]をクリック


6. ポップアップが表示されるので[Configure]をクリック


7. Permissionの設定画面が表示されるので以下にチェックを付けて[Save]をクリック

  • Device details
  • Device list
  • Device ID
  • Device notes

2.スプレッドシート(GAS)作成

  1. スプレッドシートを新規作成して適当な名前をつける
  2. メニューから[拡張機能] > [Apps Script] をクリック
  3. プロジェクト名を入力(名前は任意)
  4. 以下スクリプトをコピーして貼り付ける [コピペでOKです]
function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('実行')
    .addItem('デバイス一覧取得', 'ExportDevicesList')
    .addToUi();
}

function ExportDevicesList() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const apiKey = PropertiesService.getScriptProperties().getProperty("apikey");
  const domain = PropertiesService.getScriptProperties().getProperty("domain");
  const devicesUrl = 'https://' + domain + '.api.kandji.io/api/v1/devices/';

  const options = {
    'method': 'get',
    'headers': {
      'Authorization': 'Bearer ' + apiKey
    },
    'muteHttpExceptions': true
  };

  const response = UrlFetchApp.fetch(devicesUrl, options);
  const devices = JSON.parse(response.getContentText());

  // シートクリアして項目を追加
  sheet.clear();
  sheet.appendRow([
    'Device ID', 
    'Device UUID', 
    'Device Model', 
    'Model Identifier',     
    'CPU', 
    'RAM',
    'Disk Capacity', 
    'Disk Available', 
    'Serial Number',
    'Host Name',
    'OS Version',
    'Activation Lock', 
    'FileVault', 
    'Last Login User', 
    'User Name', 
    'Email', 
    'Last Check-In', 
    'Blueprint Name', 
    'Asset Tag', 
    'Tag', 
    'Notes'
  ]);

  // APIからの応答が配列であることを確認
  if (!Array.isArray(devices) || devices.length === 0) {
    Logger.log('No devices found or wrong data structure');
    return;
  }

  devices.forEach((device) => {
    const deviceDetailsUrl = devicesUrl + device.device_id + '/details';
    const deviceDetailsResponse = UrlFetchApp.fetch(deviceDetailsUrl, options);
    const deviceDetails = JSON.parse(deviceDetailsResponse.getContentText());
    const deviceNotesUrl = devicesUrl + device.device_id + '/notes'; 
    const deviceNotesResponse = UrlFetchApp.fetch(deviceNotesUrl, options);
    const deviceNotes = JSON.parse(deviceNotesResponse.getContentText());

    // (RAM)GB以降のテキストを削除
    let ram = deviceDetails.hardware_overview.memory || 'N/A';  
    if (ram && ram.includes('GB')) {
      ram = ram.substring(0, ram.indexOf('GB') + 2);
    }

    //(ボリューム)encryptedがYesのDISK情報のみ抽出
    let diskCapacity = 'N/A';
    let diskAvailable = 'N/A';
    if (Array.isArray(deviceDetails.volumes)) {
      for (let i = 0; i < deviceDetails.volumes.length; i++) {
        const volume = deviceDetails.volumes[i];
        if (volume.encrypted === 'Yes') {
          diskCapacity = volume.capacity || 'N/A';
          diskAvailable = volume.available || 'N/A';
          break;
        }
      }
    }

    // (Tags)有無をチェック。複数ある場合はカンマ区切りで取得
    let tagResult = '';
    if (Array.isArray(deviceDetails.tags)) {
      if (deviceDetails.tags.length !== 0) {
        tagResult = deviceDetails.tags.join(', '); // カンマ区切りで全ての要素を連結
      }
    }

    // (Notes)有無をチェック。ある場合はHTMLタグを除去、複数ある場合はカンマ区切りで結合
    let notesresult = '';
    if (Array.isArray(deviceNotes.notes)) { 
      if (deviceNotes.notes.length !== 0) {
        notesresult = deviceNotes.notes
          .map(note => note.content ? note.content.replace(/<[^>]+>/g, '') : '') 
          .filter(content => content) 
          .join(', '); 
      }
    }

    const loggedInUser = deviceDetails.general.last_user || 'N/A';                                              // ログインユーザー情報
    const processorName = deviceDetails.hardware_overview.processor_name || 'N/A';                              // Processor Nameを取得
    const activationLock = deviceDetails.activation_lock.user_activation_lock_enabled ? 'Enabled' : 'Disabled'; // アクティベーションロックの有無
    const fileVaultEnabled = deviceDetails.filevault.filevault_enabled ? 'Enabled' : 'Disabled';                // FileVaultの有効/無効を取得
    const txt_os_version = `'${device.os_version}`;

    // シートに追加
    sheet.appendRow([
      device.device_id, 
      deviceDetails.hardware_overview.udid, 
      device.model, 
      deviceDetails.hardware_overview.model_identifier,
      processorName, 
      ram, 
      diskCapacity, 
      diskAvailable, 
      device.serial_number, 
      device.device_name, 
      txt_os_version, 
      activationLock, 
      fileVaultEnabled, 
      loggedInUser, 
      device.user.name, 
      device.user.email, 
      device.last_check_in, 
      device.blueprint_name, 
      device.asset_tag, 
      tagResult,
      notesresult
    ]);
  });
}

5. 左メニューの歯車(プロジェクトの設定)を開く
6. スクリプト プロパティに以下登録して保存

プロパティ補足
apikeyKandjiで作成したAPIキー
domainサブドメインhttps://xxx.kandji.io/
URLのxxxの部分

こちらを実行すればスプレッドシートに一覧が出力されるはずです

GASの補足説明

自分が処理内容をすぐ忘れるのでたくさんコメント記載していますが、ポイントのみ補足します。

RAM情報

  • そのまま取得すると[16 GB LPDDR4]のようなフォーマットになってしまうのでGBより右のテキストを削除してます。
    // (RAM)GB以降のテキストを削除
    let ram = deviceDetails.hardware_overview.memory || 'N/A';  
    if (ram && ram.includes('GB')) {
      ram = ram.substring(0, ram.indexOf('GB') + 2);
    }

DISK情報

  • KandjiだとDISKのハードウェア情報が取得出来ないので、パーティションの中からAESが有効なDISKの情報情報を取得しています。(もっとうまく出来る方法あったら教えて下さいっ)
    //(ボリューム)encryptedがYesのDISK情報のみ抽出
    let diskCapacity = 'N/A';
    let diskAvailable = 'N/A';
    if (Array.isArray(deviceDetails.volumes)) {
      for (let i = 0; i < deviceDetails.volumes.length; i++) {
        const volume = deviceDetails.volumes[i];
        if (volume.encrypted === 'Yes') {
          diskCapacity = volume.capacity || 'N/A';
          diskAvailable = volume.available || 'N/A';
          break;
        }
      }
    }

タグ、ノートの情報

  • 複数登録出来るので複数存在する場合はカンマ区切りで取得するようにしてます。
  • またノートはHTMLとして記録されているのでタグも外すようにしました。
    // (Tags)有無をチェック。複数ある場合はカンマ区切りで取得
    let tagResult = '';
    if (Array.isArray(deviceDetails.tags)) {
      if (deviceDetails.tags.length !== 0) {
        tagResult = deviceDetails.tags.join(', '); // カンマ区切りで全ての要素を連結
      }
    }

    // (Notes)有無をチェック。ある場合はHTMLタグを除去、複数ある場合はカンマ区切りで結合
    let notesresult = '';
    if (Array.isArray(deviceNotes.notes)) { 
      if (deviceNotes.notes.length !== 0) {
        notesresult = deviceNotes.notes
          .map(note => note.content ? note.content.replace(/<[^>]+>/g, '') : '') 
          .filter(content => content) 
          .join(', '); 
      }
    }

まとめ

Kandjiには標準でデバイス一覧をCSVエクスポートする機能がありますが、取得できる情報が限られているため、今回このスクリプトを作成しました。

このGASをさらに改良すれば、取得したデータを使ってOS未更新のユーザーや長期間未接続のデバイスを検知してSlackとかで通知を送るツールを作ったり出来ると思うのでぜひ色々試してみて下さい!

最後に

当方は副業情シスとして活動もしています。

こちらのサイトに詳細記載しておりますので、もしご興味がある方いればお気軽にお問い合わせ(またはSNSでDM等)をお待ちしております。

ヤスムラ

◇基本情報
▶IT業界で働くアラフォー
▶一児の父

◇経歴/実績
▶2020年スタートアップに情シスとして転職

▶2021年に副業(情シス x ITコンサル)を開始して初年度売上100万円達成
▶2022年ITフリーランス向け副業コミュニティ(Slack)開設
▶2022年に副業売上300万円達成
▶2023年に副業売上600万円達成

ヤスムラをフォローする
KandjiMDM情シス未分類自動化
スポンサーリンク
ヤスムラをフォローする
ITでお金を豊かにするブログ

コメント

タイトルとURLをコピーしました