ASP.NET Core Web APIでSharePointの保持ラベル・コンプライアンス設定を取得しギャップ分析する方法(Microsoft Graph/CSOM)

ASP.NET Core Web API から SharePoint Online の「表示速度・検索性能・保持(リテンション)・コンプライアンス設定」を取得して、ガバナンス上の不足点(ギャップ)を自動で洗い出したい――そんな要件はよくあります。ですが実際には、APIで取得できる情報と、設計上APIでは直接取れない指標が混在します。この記事では Microsoft Graph と CSOM/PnP を軸に、実務で成立する落としどころを具体的に整理します。

目次

結論:SharePointサイトの「表示速度・検索性能」は“そのままAPI取得”が難しい

まず押さえるべきポイントは、「ページ表示速度(ロード時間)」と「検索性能(検索のパフォーマンス指標)」は、SharePointサイトの“状態”というより、利用環境・クエリ・タイミングに依存する“体験値”であることです。Microsoft Q&Aでも、SharePointサイトのロード時間や検索パフォーマンスの取得に関する公式ドキュメントが見当たらない、という回答が示されています。

一方で、保持(保持ラベル)や一部のコンプライアンス領域は、CSOMやMicrosoft Graphで“取得・適用・管理”が可能な範囲があります。

取得可否の早見表

取得したいものWeb APIからの直接取得現実的な取得手段補足
ページのロード時間(表示速度)困難合成監視(ブラウザ計測)/ 管理センターのレポート/ Page DiagnosticsUIツールはページの指標(Page load time等)を確認できる
検索パフォーマンス(性能指標)困難Search REST/CSOMで特定クエリの処理時間を計測、または管理レポートに寄せる検索API自体はあるが「サイトの検索性能」指標を丸ごと返すAPIではない
保持ラベル(ファイル/フォルダに付いたラベル)可能Microsoft Graph(driveItem retentionLabel)アプリ権限でも取得可能
保持ラベルの適用(ファイル/フォルダ)可能Microsoft Graph(driveItem: setRetentionLabel)/ CSOMラベルポリシー未発行でも適用できる旨が明記
保持ラベル定義一覧(テナントのラベル一覧)条件付きGraph(security/labels/retentionLabels)このAPIはアプリ権限非対応(=サーバー常駐の完全自動化に不向き)
コンプライアンス “ギャップ”の自動抽出不可「期待状態」を定義して差分比較で自作ギャップ一覧を返すGraph APIは無い(by design)

ページ表示速度をどう扱うべきか

SharePointのページ表示速度は、ネットワーク(拠点/回線/プロキシ)、端末性能、ブラウザキャッシュ、ページのWebパーツ構成などに強く依存します。つまり、Web APIがサーバー側で値を1つ返しても、それがユーザー体験の代表値になりません。

代替案:合成監視(ブラウザ計測)で“同じ条件”の速度を作る

「APIで取得できないなら、API側で計測してしまう」という発想が実務では効きます。具体的には、Playwrightなどのヘッドレスブラウザで対象ページを開き、ナビゲーション時間や主要イベント(DOMContentLoaded等)を計測します。

ただし、SharePointはサインインや条件付きアクセス、MFAが絡むことが多く、単純なID/パスワード自動ログインは現実的でないケースがあります。その場合は以下のように設計を分けるのが安全です。

パターン向いている状況注意点
RUM(Real User Monitoring)実ユーザーの体感速度を集めたい社内ポリシー、個人情報・ログ設計が必要
合成監視(ヘッドレス)同一条件で比較したい(改善・劣化検知)認証の壁、サイトごとのアクセス制御に注意
管理センター/診断ツール寄せMicrosoft推奨の観点で分析したい“APIで吸い上げる”より“運用で見る”に寄る

Page Diagnostics と Site performance page を使う考え方

SharePointには、ブラウザ拡張の Page Diagnostics for SharePoint があり、ページを一定のルールで分析し、相関IDやSPRequestDuration、Page load timeなどの情報を確認できます。

また、SharePointの Site performance page(サイトのパフォーマンスページ)に関する案内もあり、ページ改善の導線としてはここに寄せるのが現実的です。

重要なのは、「速度の取得」をWeb APIの責務にしないことです。Web APIは“結果を集約して見せる”役に寄せ、計測は専用ジョブ(監視)に分離すると、運用が崩れにくくなります。

検索性能(検索パフォーマンス)をどう扱うべきか

「検索性能」と一口に言っても、

  • 検索クエリの種類(KQL/FQL、絞り込み、ソート、リファイナー)
  • インデックス状況(更新直後か、クローリング状況)
  • 結果ソース、権限トリミング、対象コンテンツ量

などで大きく揺れます。したがって、管理者が見たい“検索の健全性”や“遅延傾向”を、単一APIで返すような作りにはなっていません。(Microsoft Q&Aでも検索性能のドキュメントは見当たらない旨が示されています) 。

できること:Search REST / Search Query API で“特定クエリ”の処理時間を測る

SharePointには検索クエリAPIが用意されており、RESTで /_api/search/query を叩けます。

これを使うと、あなたのWeb API側で「代表クエリ」をいくつか固定し、レスポンスの処理時間やHTTPの往復時間を記録して、“検索が遅い/速い”を時系列で観測できます。

ただしこれはあくまで「そのクエリの結果が返るまでの時間」であり、ユーザーの検索体感(UI描画、端末、ネットワーク)とは一致しません。ここを混同しないことが、設計で最も重要です。

Search RESTでの計測イメージ(HTTP)

GET https://{tenant}.sharepoint.com/sites/{site}/_api/search/query?querytext='sharepoint'&clienttype='GovernanceScanner'
Accept: application/json;odata=nometadata

Web API側では、

  • HTTP往復時間(Stopwatch)
  • (返ってくるなら)レスポンス内の処理時間っぽい値(例:ElapsedTime)

をログ化して、ダッシュボードで可視化します。

保持(リテンション)をWeb APIから扱う:Graph と CSOM を使い分ける

保持は、SharePointのガバナンス自動化で最も成果が出やすい領域です。理由は単純で、「アイテムに何の保持ラベルが付いているか」は、APIで状態として取り扱いやすいからです。

Graphで「ファイル/フォルダに付いた保持ラベル」を取得する

Microsoft Graphには、driveItemに適用された保持ラベルを取得するAPIがあります。アプリ権限でも利用できるため、バックエンドの定期スキャンに向いています。

GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/retentionLabel
Authorization: Bearer {token}

レスポンスにはラベル名や、保持期間中の挙動(削除可否、レコードロック等)が含まれます。

Graphで保持ラベルを適用する(driveItem: setRetentionLabel)

保持ラベルの適用もGraphで可能です。さらに、ラベルポリシーで“発行”されていなくても適用できる旨が明記されています。

PATCH https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/retentionLabel
Content-Type: application/json
Authorization: Bearer {token}

{
  "name": "Retention label for Contracts"
}

なお、レコードとして分類する保持ラベルを変更する場合に必要な最小権限など、権限面の注意点もドキュメントに記載があります。

CSOMで保持ラベルを扱う(大量適用・既存資産に強い)

SharePoint開発者向けには、CSOMで保持ラベル(ComplianceTag)を適用する方法が整理されています。特に大量適用は SetComplianceTagOnBulkItems の利用が強く推奨されています。

「Graphで取得・適用」「CSOMでバルク」という住み分けは、実装と運用の両方でバランスが良いです。

保持ラベル定義(テナントに存在するラベル一覧)を取りたい場合の落とし穴

“ラベル定義の一覧”をGraphで取得するAPI(/security/labels/retentionLabels)はありますが、現時点のドキュメントではアプリケーション権限がサポートされません。つまり、サーバー側で完全自動(アプリのみ)で毎晩同期する、のような設計にはそのままでは向きません。

この制約があるため、実務では次のどちらかに寄せることが多いです。

  • ラベル定義は「人が管理」(Purview側で変更があれば運用で反映)し、Web APIは“付いている/付いていない”を中心に見る
  • 管理者がサインインする管理画面に限って、委任権限(delegated)でラベル一覧を取得し、内部DBに保存して使う

コンプライアンス設定を“サイト単位”で取得したいときにハマるポイント

「コンプライアンス設定」と言った場合、実際には複数の領域が混ざります。

領域例サイト単位での判定の難しさ
情報ガバナンス/レコード管理保持ラベル、レコード化、削除制御アイテム状態は追えるが、ポリシーの“適用判定”は自前になりがち
訴訟対応(eDiscovery)ケース、ホールド、検索、エクスポート“サイトの良し悪し”というより法務ワークフローの領域
サイト分類/感度ラベル分類(Classification)/ Sensitivity labels分類は取得できるが、テナント方針との突合が必要

eDiscoveryはGraphで自動化できるが、“ギャップ検出”とは別物

Microsoft Graph(security)には eDiscovery ケースの一覧取得などのAPIがあり、アプリ権限でも呼び出せます。

ただし、これは「訴訟/調査のためのケース運用」を自動化するAPIであり、SharePointサイトの“コンプライアンス不足点”を列挙する用途とは性格が異なります。

サイト分類(Classification)をガバナンス項目として使う

モダンサイトの分類(Classification)は、ガバナンスやコンプライアンス観点でサイト群を整理する目的で用いられ、CSOM/RESTで読める旨が案内されています。

また、サイト分類の代わりに感度ラベルを使う流れも示されています。

ギャップ分析の観点では、分類・感度ラベルは「必須」「部門別に指定」などの“期待状態”が作りやすく、差分比較がしやすい項目です。

「ギャップ(不足)」はAPIが返してくれない:差分比較の設計にする

“このサイトはガバナンス不足です”という結果をそのまま返すGraph APIは存在しない、という扱いがMicrosoft側から示されています。

したがって実装は、必ず次の形になります。

  1. あるべき状態(期待ポリシー/必須ラベル/設定値)を定義する
  2. Graph/CSOM/PnPで取得できる範囲の情報を収集する
  3. 差分比較して、ギャップをレポート化する

ギャップ判定チェックリスト例

チェック観点期待値例収集元判定のコツ
ドキュメントに保持ラベルが付いている重要ライブラリは“未ラベル率0%”Graph(driveItem retentionLabel)まずは“未ラベル件数/率”で十分。全件の詳細チェックはコストが高い
レコード化ラベルの運用契約書はRecordラベル必須Graph/CSOMレコード系は権限制御が絡むので“適用有無”を軸に
サイト分類(Classification)部門サイトは必ず分類ありCSOM/REST(Site.Classification)分類値の一覧と、部門のマッピング表を持つと判定が安定
検索の劣化検知代表クエリの応答が閾値以内Search REST + 自前計測サイト全体の“検索性能”ではなく“代表クエリのSLO”として管理する
ページ表示の劣化検知代表ページのLoad時間が閾値以内合成監視/診断ツールWeb APIが返す値ではなく監視結果をAPIが集約する

ASP.NET Core Web APIでの実装パターン

「Web APIから取得したい」という要望を、無理なく実装に落とすなら、API=即時取得にせず、スキャン=バッチ/ジョブに寄せるのがコツです。理由は、サイト/ファイル数が増えるほど、同期処理はタイムアウト・スロットリング・コスト爆発のリスクが高いからです。

推奨アーキテクチャ(実務で壊れにくい)

コンポーネント役割例
スキャナー(バックグラウンド)Graph/CSOMで収集してDBへ保存Hangfire / Azure Functions / WebJobs
Web API保存済み結果を返すASP.NET Core Minimal API / Controller
ストレージサイトごとの最新スキャン結果、履歴SQL / Cosmos DB / Table Storage
ダッシュボードギャップ一覧・推移・担当者アサインPower BI / 独自Web

Graphで保持ラベル状況を収集する流れ(概念)

  1. 対象サイトをGraphで特定(siteId取得)
  2. サイト内のドライブ(ドキュメントライブラリ)一覧を取得
  3. 各ドライブをdelta等で走査してdriveItemを列挙
  4. 各driveItemに対して retentionLabel を取得
  5. 「未ラベル」「期待ラベルと違う」をギャップとして記録

このとき、SharePoint Onlineはスロットリング(429/503)を返すことがあり、Retry-Afterを尊重するなどの実装が必須です。特にGraph/CSOM/RESTいずれの呼び出しも対象になり得る点が明記されています。

スロットリング前提の実装ポイント

  • 並列数を抑える(サイト単位、ドライブ単位でキュー制御)
  • Retry-Afterを尊重して指数バックオフ
  • deltaの活用で“全件走査”を避ける(前回差分だけ取る)
  • エラー時に“途中結果”を保存し、次回リトライで続きから再開できる設計

ギャップ判定ルールの持ち方(例:JSONで期待状態を定義)

{
  "sites": [
    {
      "siteUrl": "https://contoso.sharepoint.com/sites/Contracts",
      "requiredClassification": "HBI",
      "requiredLibraries": [
        { "libraryName": "Shared Documents", "requiredRetentionLabel": "Retention label for Contracts" }
      ],
      "thresholds": {
        "maxUnlabeledRate": 0.0,
        "maxSearchQueryMs": 1500,
        "maxSyntheticLoadMs": 4000
      }
    }
  ]
}

この“期待状態”があるからこそ、Graph/CSOMで取れる情報を並べて差分でギャップにできます。APIがギャップを返してくれない以上、ここが設計の肝です。

実装例:保持ラベル取得(C# / 疑似コード)

Microsoft Graph SDKのバージョンや生成されるクライアント形状は変わるため、ここでは処理の骨格を示します。

using Azure.Identity;
using Microsoft.Graph;

var tenantId = Environment.GetEnvironmentVariable("TENANT_ID");
var clientId = Environment.GetEnvironmentVariable("CLIENT_ID");
var clientSecret = Environment.GetEnvironmentVariable("CLIENT_SECRET");

// アプリ権限(client credentials)の例
var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(credential, new[] { "https://graph.microsoft.com/.default" });

// 1) サイト特定(例:事前にsiteIdを把握している前提)
var siteId = "{site-id}";

// 2) ドライブ(ドキュメントライブラリ)列挙
var drives = await graphClient.Sites[siteId].Drives.GetAsync();

foreach (var drive in drives.Value)
{
    // 3) drive配下のアイテムを列挙(本番はdelta推奨)
    var children = await graphClient.Drives[drive.Id].Root.Children.GetAsync();

    foreach (var item in children.Value)
    {
        // 4) 保持ラベル取得
        // GET /drives/{drive-id}/items/{item-id}/retentionLabel
        var label = await graphClient.Drives[drive.Id].Items[item.Id].RetentionLabel.GetAsync();

        // 5) ギャップ判定(例)
        var isUnlabeled = (label == null || string.IsNullOrEmpty(label.Name));
        // ...DBに保存/集計
    }
}

driveItem retentionLabel の取得/適用はGraphドキュメントに明確に記載されており、アプリ権限でも使える点が重要です。

「不足点を洗い出す」レポート設計のコツ

ギャップ分析レポートは、最初から完璧を狙うと破綻しやすいです。おすすめは、次の順で段階的に価値を出すことです。

  1. 未ラベル率(保持ラベルが付いていないファイルの割合)
  2. 期待ラベルとの差分(契約書ライブラリなのに別ラベル、など)
  3. レコード化の運用差分(ロックや更新制御の想定違い)
  4. 分類/感度ラベルの不一致(部門ルールと違う)
  5. 最後に、検索/ページ速度は監視結果の集約として統合

ギャップ出力(例:APIが返すJSONイメージ)

{
  "siteUrl": "https://contoso.sharepoint.com/sites/Contracts",
  "scannedAt": "2026-01-03T00:00:00Z",
  "summary": {
    "totalItemsScanned": 1250,
    "unlabeledItems": 37,
    "unlabeledRate": 0.0296
  },
  "gaps": [
    {
      "type": "RetentionLabelMissing",
      "target": "Shared Documents/2024/Contract-001.docx",
      "expected": "Retention label for Contracts",
      "actual": null,
      "severity": "High"
    },
    {
      "type": "ClassificationMismatch",
      "target": "Site",
      "expected": "HBI",
      "actual": "MBI",
      "severity": "Medium"
    }
  ]
}

機能追加要望(ギャップ検出APIが欲しい場合)

「ギャップをAPIで返してほしい」という要求そのものは自然ですが、現状はby designで存在しない旨が示され、フィードバックポータルへ要望を上げる案内があります。

参考ドキュメント(原文URL)

https://learn.microsoft.com/en-us/sharepoint/dev/apis/csom-methods-for-applying-retention-labels
https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/modern-experience-site-classification
https://learn.microsoft.com/en-us/graph/api/driveitem-getretentionlabel?view=graph-rest-1.0
https://learn.microsoft.com/en-us/graph/api/driveitem-setretentionlabel?view=graph-rest-1.0
https://learn.microsoft.com/en-us/graph/api/security-labelsroot-list-retentionlabel?view=graph-rest-1.0
https://learn.microsoft.com/en-us/microsoft-365/enterprise/page-diagnostics-for-spo?view=o365-worldwide
https://learn.microsoft.com/en-us/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online
https://learn.microsoft.com/en-gb/answers/questions/2128386/how-to-retrieve-sharepoint-site-load-times-search
https://feedbackportal.microsoft.com/feedback/

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次