AIでSaaSライセンスを棚卸しする方法|購入枠・割当経路・利用記録を分ける

架空の2製品・割当7経路を照合し、製品別6組と5人を区別。未割当枠と、利用記録の未取得・期間外の新規割当を確認質問へ整理します。

AIものさし編集部

AIでSaaSライセンスを棚卸しするときは、購入した枠、利用者への割当、利用記録を別々に照合します。割当一覧に名前がないことと、使っていないことは同じではありません。利用記録が見つからない人を、そのまま解除や解約の対象にもしません。

この記事では、架空の2製品の購入枠と割当経路を整理し、利用記録の確認質問を作ります。契約の変更、アカウント操作、ライセンス解除は行いません。実際のテナント、API、AI分析、節約効果を検証した例ではありません。

製品、契約、割当先の単位をそろえる

Microsoft 365の公式説明では、Licensesページで同一製品の複数契約を合算表示する場合があり、Your productsページの契約ごとの表示とは異なります。また、直接割当は利用者、グループ割当はグループ名が表示されるため、画面の行数をそのまま利用者数にはできません。Microsoft:ライセンスの割当(新しいタブで開く)

まず、製品・組織・契約期間・集計時点・課金単位を確認します。以下は特定の製品やMicrosoft 365の契約を再現したものではなく、同一製品を同一ユーザーへ複数経路で割り当てても、この例では1枠として数える架空の条件です。別製品への割当は別枠とします。

購入枠は2026年10月20日時点でA製品8枠、B製品3枠です。別製品の余りを交換できる条件はありません。無効な割当、処理中、割当失敗は今回の入力へ含めず、次の行はすべて有効な割当経路とします。

割当経路の行数と、利用者・製品の組を分ける

表は横にスクロールできます

元行製品ユーザーID割当経路
A01AU01直接
A02AU02直接
A03AU02グループG01
A04AU03グループG01
A05AU04直接
B01BU01直接
B02BU05直接

この表は、グループ所属をユーザー単位へ展開した独自の架空表です。管理画面の出力形式ではありません。元の割当経路を残してから、製品とユーザーの列の組で数えます。A02とA03は同じA・U02へ対応しますが、片方の行を原資料から削除するという意味ではありません。

表は横にスクロールできます

数えるもの今回の値
割当経路の行7行
異なる製品・ユーザーの組6組:Aが4、Bが2
両製品を通じた異なるユーザー5人
購入枠と割当済みの差Aは8−4=4枠、Bは3−2=1枠

U01は両製品にいます。5人という人数だけを購入11枠から引くと、今回の製品別の割当を再現できません。一方、Aの5経路を5枠と数えると、A02・A03を二重に計上します。

差のA4枠・B1枠は、この例の条件での未割当枠です。購入が不要だった枠、今すぐ減らせる契約数、返金額とは言い換えません。将来の利用予定、最低契約数、更新条件が分からないためです。

利用記録は、取得範囲と時点を先に見る

Microsoft Graphの利用者レポート仕様には、Report Refresh Date、サービス別の最終利用日、割当日などが別の列として示されています。集計期間の指定もあるため、現在の割当一覧と、過去の利用レポートを同じ時点の値として扱わないようにします。Microsoft Graph:利用者レポート(新しいタブで開く)

今回、A製品について用意した架空の確認表は次のとおりです。利用レポートの対象期間は9月19日~10月18日、更新日は10月18日という設定で、10月20日時点の割当一覧とは時点が異なります。この期間は独自例で、Graphの実レスポンスではありません。

表は横にスクロールできます

ユーザー架空の利用情報今回言えること
U01対象期間内の利用記録ありその期間内の記録を確認
U02対象範囲の記録を取得済みで、期間内利用記録なし期間内の記録なし。利用不要とは未確認
U03利用情報を取得できていない判定不能。未使用へ変えない
U0410月20日に初めて割当期間終了後の割当。対象期間で利用を評価しない

Aの割当先4人は、期間内利用の記録あり1人、取得範囲内の記録なし1人、情報未取得1人、期間終了後の新規割当1人に分かれます。「4人中3人が未使用」とは書けません。B製品の利用情報は今回提供していないため、Bの2人も判定していません。

サービス別の記録で、製品全体や全業務の利用を観測できるとも限りません。必要な業務、別の利用経路、休暇、利用開始予定などは、この表に含まれていません。AIへ理由を補完させず、確認先へ質問として返します。

固定例の枠数と分類を検算する

次のPythonは、架空の有効割当経路を数える例です。setは計数用に製品・ユーザーの組を作りますが、元の7行は残します。

from collections import Counter

purchased = {"A": 8, "B": 3}
paths = [("A01", "A", "U01"), ("A02", "A", "U02"),
         ("A03", "A", "U02"), ("A04", "A", "U03"),
         ("A05", "A", "U04"), ("B01", "B", "U01"),
         ("B02", "B", "U05")]
pairs = {(product, user) for _, product, user in paths}
assigned = {p: sum(product == p for product, _ in pairs) for p in purchased}
unassigned = {p: purchased[p] - assigned[p] for p in purchased}
assert len(paths) == 7 and len(pairs) == 6
assert len({user for _, user in pairs}) == 5
assert assigned == {"A": 4, "B": 2}
assert unassigned == {"A": 4, "B": 1}
a_usage = {"U01": "OBSERVED", "U02": "NO_RECORD_IN_SCOPE",
           "U03": "UNKNOWN", "U04": "ASSIGNED_AFTER_WINDOW"}
assert set(a_usage) == {user for product, user in pairs if product == "A"}
assert Counter(a_usage.values()) == {
    "OBSERVED": 1, "NO_RECORD_IN_SCOPE": 1,
    "UNKNOWN": 1, "ASSIGNED_AFTER_WINDOW": 1,
}
print(assigned, unassigned, a_usage)

掲載例はローカルで実行し、別の検算でもユーザーごとの製品対応と元行から、A4組・B2組、A02・A03の同一組を確認しました。利用情報の4分類は、この例で与えた確認結果の計数であり、利用ログを自動判定する処理ではありません。

実際には、グループの未展開、割当エラー、ユーザーIDの変更、利用停止済みのアカウント、製品の重複権利などを確認します。氏名が同じという理由で別IDを一人へまとめず、余りが負数になったら値を0へ丸めずに入力と数え方を見直してください。

AIへは、解除候補より確認質問を返させる

架空の購入枠と有効な割当経路、A製品の利用確認表を整理してください。
この例では同一製品・同一ユーザーの複数経路を1枠と数えます。元行は残してください。
製品別の購入枠、割当組数、差を示し、人数と経路数を混同しないでください。
利用情報は記録あり、対象範囲内の記録なし、未取得、期間終了後の割当を分けてください。
未割当枠を削減可能数、記録なしを不要な利用権と断定しないでください。
出力:元行付きの計数、情報の期間と更新日、不明点、確認質問。
ライセンス解除、アカウント変更、契約変更、管理者への送信は行いません。

確認質問の例は、「U02には今回の記録で観測できない利用や今後の業務予定があるか」「U03の利用情報は取得できるか」「U04の利用開始後にどの期間で見直すか」「A4枠・B1枠に割当予定があるか」です。これは文案で、本人や管理者へ実際に問い合わせた結果ではありません。

Microsoftの公式資料も、利用者から割当を外す操作と、契約のライセンス数を減らす判断を別に扱っています。割当解除にはデータや利用への影響もあるため、件数表を作っただけで変更へ進みません。確認した資料、判断者、利用への影響、契約条件がそろってから、実際の変更を別の作業として扱ってください。

参考資料

公式資料の確認日:2026年10月20日。製品、購入枠、割当経路、利用情報、集計条件は独自の架空例です。掲載コードと別方式の計数をローカルで検査しました。実テナント、API取得、AI処理、利用の必要性、契約削減、料金効果、解除やデータへの影響、画面表示は未検証です。

質問から自分に合うAIを探す