SharePoint Online で「ユーザー情報リスト(User Information List)」を参照したいのに、Microsoft Graph だと list not found になって詰まることがあります。原因は「リストが無い」ではなく、システム(隠し)リスト特有の見え方・指定方法にあるケースが大半です。この記事では、現象の整理から、Graph で確実に特定して取得する手順、うまくいかない場合の現実的な回避策までをまとめます。
現象:Graph で「User Information List」を叩くと list not found になる
よくあるのが、次のようにリストの表示名(見た目の名前)を URL に入れて取得しようとして失敗するパターンです。
GET https://graph.microsoft.com/v1.0/sites/{siteId}/lists/User Information List/items?$expand=fields
返ってくる典型的なエラーは、HTTP 404(itemNotFound / list not found)です。
一方で SharePoint REST API の /_api/web/GetUserById(id) などではユーザー情報が取れてしまうため、「リストは存在しているはずなのに Graph では見つからない」という状況になります。
前提知識:User Information List は“普通のリスト”ではない
User Information List(ユーザー情報リスト)は、SharePoint が内部的に利用するユーザー情報の保管場所です。People Picker(ユーザー/グループ列)やワークフロー等で参照され、Person/Group 列の “LookupId” がこのリストのアイテム ID を指す、という場面に遭遇します。
また、このリストはサイトの「サイトのコンテンツ」に常に表示されるわけではなく、管理者であれば URL から直接表示できることがあります(例:/_catalogs/users/ 配下)。
この“システム管理の隠しリスト”という性質が、Graph 側での扱い(列挙や名前解決)に影響します。Graph のリスト取得は可能でも、「表示名での参照」は環境差に弱く、同じ URL でもサイトによって成否が分かれがちです。
なぜ Graph で list not found になるのか(原因の全体像)
「list not found」は“本当に存在しない”以外にも、いくつかの原因で起きます。特に User Information List は複数の要因が重なりやすいので、まずは原因候補を分解して捉えるのが近道です。
| 原因候補 | 起きやすい状況 | 確認ポイント | 基本の対処 |
|---|---|---|---|
| システム(system facet)扱いで、既定の列挙に出てこない | Graph で /lists を見ても見当たらない | /sites/{siteId}/lists?$select=system を試す | system を含めて列挙し、ID でアクセス |
| 表示名が環境(言語/テンプレート/移行履歴)で変わる | テストサイトは OK、本番だけ NG | Graph の一覧で displayName を確認 | 表示名ではなく listId に切り替える |
| Graph の“リストタイトル指定”がシステムリストで安定しない | /lists/{list-title} 形式で 404 | 同じ listId なら取れるか | タイトル指定をやめ、GUID(listId)で取得 |
| 権限不足だが、セキュリティトリミングで 404 に見える | 403 ではなく 404 が返る | 同トークンで他リストは取れるか、管理者で試す | 権限/サイト権限付与の見直し、別 API の併用 |
| サイト ID が“目的の範囲”とズレている(ルート/サブサイト) | サブサイトの siteId で叩いている | ルートサイトの siteId で再検証 | 対象が存在する site の siteId を使う |
この中で最も多いのが「system facet のために既定では見えない」「表示名での参照が不安定」という2つです。Microsoft Learn のドキュメントでも、system facet を持つリストは既定で隠れるため、列挙するには $select に system を含める必要がある、と明記されています。
結論:まず“リスト ID(GUID)”を特定して、それで叩く
Graph でシステム/隠しリストを扱うときは、「表示名を URL に入れて直接アクセス」よりも、次の流れが安定します。
- Graph でリスト一覧を列挙し、User Information List 相当の listId を特定
- 特定した listId で
/lists/{listId}/itemsを叩く
Graph のリスト(list)には displayName と id があり、さらに system(system facet)を持つ場合は「システム管理のリスト」であることが分かります。
手順:system リストも含めて列挙する
まずは list 一覧を取得します。ここがポイントで、system facet を持つリストは既定で隠れるため、$select に system を含めて列挙します。
GET https://graph.microsoft.com/v1.0/sites/{siteId}/lists?$select=id,displayName,name,webUrl,list,system
(環境や SDK によっては name だけ/ displayName だけが目立つ形で返ることがありますが、いずれにしても listId(id)を拾うのが目的です。)
もし既存の実装が /v1.0 でうまく列挙できない場合、Microsoft Q&A などでは /beta で $select=system を付ける方法が案内されることもあります。まずは v1.0 を試し、難しければ検証用途で beta も使って挙動確認すると切り分けが早いです。
一覧から User Information List を見つけるコツ
「displayName が “User Information List” のものを探す」が分かりやすいですが、言語設定・移行元環境・サイトテンプレート等で表示名が揺れる可能性があります。そこで、次の複数条件で“それっぽさ”を判定すると現場では安定します。
| 見るべきプロパティ | 期待する特徴 | 狙い |
|---|---|---|
system | 存在する(system facet を持つ) | “システム管理”の候補に絞る |
list.hidden | true のことが多い | “隠しリスト”らしさで絞る |
list.template | ユーザー情報系のテンプレート値になることがある | テンプレートから同定する |
webUrl | /_catalogs/users/ に近い URL になることがある | URL からユーザー情報リスト系と推測 |
list.template は SharePoint の SPListTemplateType に対応する値で、未知の値も返り得るため「列挙されていない値が来ても壊れない実装にする」と公式にも注意書きがあります。
SharePoint 側のテンプレート体系としては User Information のテンプレート ID が 112(UserInformation)として整理されているため、SharePoint REST / CSOM / 移行ツールの文脈で「112 のリスト=ユーザー情報」と見なせる場面もあります。
listId が取れたら、ID で items を取得する
listId(GUID)が分かったら、次の形で items を取得します。
GET https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{listId}/items?$expand=fields
さらに、取得するフィールドを絞るとレスポンスが軽くなり、パフォーマンス・転送量・タイムアウト耐性が上がります。Graph の list items API は $expand=fields(select=...) の形をサポートしています。
GET https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{listId}/items?expand=fields(select=Title,EMail,UserName)
※User Information List の列名(内部名)はテナントやカスタマイズで差が出る可能性があります。最初は expand=fields で全体像をつかみ、次に必要項目へ絞るのが安全です。
「/lists/User Information List」で失敗しやすい理由をもう少し具体的に
Microsoft Learn の「Get metadata for a list」では、/sites/{site-id}/lists/{list-title} のように“リストタイトルで取得”できる例が掲載されています。つまり、タイトル指定は機能として存在します。
それでも User Information List で失敗しやすいのは、次の事情が重なりやすいからです。
- システムリスト(system facet)で、列挙・参照の扱いが通常リストより厳しい
- 表示名(displayName/list-title)が「英語固定」ではなく、環境要因で揺れる
- “タイトルでの解決”より、GUID(listId)前提のほうが確実
要するに、Graph 側で安定させるには「見た目の名前に依存しない」ことが最大のコツです。
それでも列挙で見つからない/見えてもアクセスできない場合の現実解
現場では、次のどちらかに寄せると解決が早く、運用も安定します。
回避策:SharePoint REST API で listId を突き止めて Graph へ“橋渡し”する
Graph の列挙がどうしても不安定なときは、SharePoint REST API でリスト情報を取り出し、そこで得た GUID を Graph に持ち込むルートが堅実です。
例えば SharePoint REST 側で「ユーザー情報(BaseTemplate=112)」を探すイメージです(例示)。
GET https://{tenant}.sharepoint.com/sites/{site}/_api/web/lists?$filter=BaseTemplate eq 112&$select=Id,Title,Hidden,BaseTemplate
このとき取れた Id(GUID)を、Graph の /lists/{listId} に渡します。
GET https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{listId}/items?expand=fields
Graph と REST を混ぜるのは“美しくない”と感じるかもしれませんが、User Information List のようなシステム領域は、割り切って併用したほうがトータル工数が下がるケースが多いです。
回避策:User Information List を“見に行く目的”を見直す
そもそも User Information List を読みに行く背景は、次のどちらかが多いはずです。
- Person/Group 列の LookupId(= ユーザー情報リストのアイテム ID)から、表示名やメールを解決したい
- サイトに出入りしたユーザー一覧のようなものを取りたい
前者(LookupId の解決)が目的なら、設計として「LookupId に依存しない」ほうが長期的に強いです。LookupId はサイトコレクションごとに別物で、同じユーザーでも別サイトでは別 ID になり得ます。移行・復元・コピーでさらにズレます。
おすすめは次の設計です。
| やりたいこと | ありがちな実装 | 長期運用でのおすすめ |
|---|---|---|
| ユーザーを一意に扱いたい | LookupId を保存 | Entra ID のユーザー ID(Graph の /users の id)や UPN/メールを保存 |
| 表示名・メールを表示したい | User Information List を参照 | Graph のディレクトリ(/users)で解決し、サイト依存を減らす |
| サイトに“現れたユーザー”一覧が欲しい | User Information List を全件取得 | 用途が本当に必要か再確認(件数が増えるほど重い) |
特に「LookupId からの解決」は、一見すると User Information List を読めば済みますが、実は“そのユーザーがサイトに一度もアクセスしていないとリストに存在しない”という仕様的な落とし穴があります。Microsoft Q&A でも、ユーザーがサイトにアクセスし、少なくとも一度サインインして初めて User Information List に追加される、という趣旨の説明があります。
つまり「LookupId があるのに User Information List に該当行がない」現象は、バグではなく“サイト側にまだ登録されていないユーザー”が原因になり得ます。ここを踏まえると、ディレクトリ(Graph のユーザー)を主軸にしたほうが堅い場面が増えます。
Graph での“特定〜取得”を安定させる実践テクニック
テクニック:列挙は「system を含める」「必要な列だけ選ぶ」
まず列挙時に system を含めるのが大前提です。system facet を持つリストは既定で隠れるため、$select に system を含める、というのが公式のルールです。
さらに、列挙で返すプロパティを絞ると読みやすく、レスポンスも安定します。
GET https://graph.microsoft.com/v1.0/sites/{siteId}/lists?$select=id,displayName,webUrl,list,system
テクニック:リストのテンプレート・hidden を同時に見る
Graph の listInfo には hidden と template が含まれます。template は SharePoint のテンプレート種別に対応するため、システムリストを同定するヒントになります。
列挙結果から「system がある」「hidden が true」「template がそれっぽい」の三点セットで拾うと、表示名が日本語/英語で揺れても追跡できます。
テクニック:items は “fields を絞る” + “ページング前提”
User Information List は利用が進んだサイトほど件数が増えます。items 取得は次の2点を前提にしておくと、運用が破綻しづらいです。
$expand=fields(select=...)で必要項目のみ取得する@odata.nextLinkが返る前提でページング実装する
Graph の list items API は $expand と $filter をサポートし、条件により複数ページで返る可能性があることも明記されています。
よくある質問と追加の落とし穴
「Sites.Read.All があるのに 404 になる」のはなぜ?
Graph/SharePoint では、権限やセキュリティトリミングの都合で「権限がない=403」ではなく「存在しないように見せる=404」になるケースがあります。特にシステム系のリソースはこの挙動を踏みやすいので、次の切り分けが有効です。
- 同じトークンで通常リスト(ユーザー作成のリスト)の items は取れるか
- サイトコレクション管理者のアカウント(delegated)で試すと挙動が変わるか
- Graph で listId 指定なら取れるのに、list-title 指定だけ落ちるか
「list-title 指定だけ落ちる」なら、権限問題より“名前解決・見え方の問題”の可能性が上がります。
「User Information List を Graph で列挙しても出ない」
まず system facet を含めずに列挙していないかを確認します。system facet のリストは既定で隠れるため、$select に system を入れた列挙が必要です。
それでも出ない場合は、次のように“Graph の列挙はうまくいかないが、ID が分かれば items は取れる”というパターンもあるため、REST/PnP など別経路で ID を取得するのが現実的です。
まとめ:この問題は「リストが無い」ではなく「見え方と指定方法」の問題
SharePoint Online の User Information List は、システム(隠し)リストとして扱われるため、Microsoft Graph で表示名どおりに参照できないケースがあります。まずは Graph でリストを列挙し(system facet を含める)、listId を特定してから items を取得する流れに切り替えると、テスト/本番の差分を吸収しやすくなります。
もし列挙や参照がどうしても不安定なら、SharePoint REST API で listId を突き止めて Graph に橋渡しする、またはユーザー解決そのものをディレクトリ(Graph の /users)中心に再設計する、という“落としどころ”が結果的に堅い選択になります。

コメント