6 月に 複数管理者承認が Graph API 経由の自動化にも適用されるようになったという短い記事を公開したところ、本サイトで最も読まれたページの 1 つになり、その後届いたメールはすべて同じことを尋ねていました。何が変わったのかではなく、どうスクリプト化するのか、です。本ガイドはその実践的な手順書です。2026 年 10 月時点で複数管理者承認 (MAA) が何を保護するのか、自分を締め出さずにアクセス ポリシーと承認者グループをどう設計するか、人間の承認者が管理センターで行う正確な操作、そして多くの方が知りたかった部分、すなわち保護対象オブジェクトを作成するスクリプトがどう承認要求を受け取り、どう待ち、承認者が Graph からどう承認し、スクリプトがどう仕事を終えるのかを扱います。ここに挙げるエンドポイント、ヘッダー、権限、制限はすべて Microsoft Learn で確認済みです。私自身の意見を加える箇所では、そう明記します。
複数管理者承認とは何か、なぜ Graph 自動化まで対象になったのか
Microsoft Learn の概要によれば、MAA のアクセス ポリシーは「変更が適用される前に、2 つ目の管理アカウントがその変更を承認することを要求」します。アクセス ポリシーは保護するプロファイル種類を 1 つと、その種類の変更を承認できるアカウントのグループを指定します。どのアカウントが保護対象リソースを変更しても、Intune は別のアカウントが明示的に承認するまで変更を保留し、承認者は拒否することもできます。業務上の理由、承認者のメモ、決定はすべて Intune の監査ログに記録されます。
2026 年 6 月までは、対話型 (委任) の管理者操作だけが傍受されていました。サービス プリンシパルがアプリ専用トークンで同じワイプやスクリプト展開を実行すると、そのまま通ってしまったのです。Microsoft は 2026 年 6 月 22 日の週の What’s new 項目でこの穴を塞ぎました。「複数管理者承認 (MAA) は、対話型の管理者操作だけでなく、Microsoft Graph API を通じて自動化が行う API 呼び出しにも適用されるようになりました。」これには 2 つのガードレールが付いています。API 呼び出しへの適用は、MAA のアクセス ポリシーを既に設定しているテナントだけが対象で、どこかで MAA を勝手に有効化することはありません。また、Graph API のハウツーによれば「MAA は保護対象リソースを変更する操作 (POST、PATCH、PUT、DELETE) にのみ適用されます。読み取り専用の操作 (GET) は影響を受けません。」
Microsoft がこうした理由は、攻撃者の視点で考えれば明らかです。DeviceManagementManagedDevices.ReadWrite.All を持つアプリのクライアント シークレットが漏れれば、以前はテナント全体のワイプ ボタンそのものでした。今では同じ呼び出しは承認要求を生むだけで、人間が読むまで何も起きません。
保護対象リソース
概要ページには 7 種類のリソースが列挙されています。Graph の operationApprovalPolicyType 列挙にはもっと多くの値 (autopilot、windows365、endpointPrivilegeManagement、filter、appProtectionPolicy など) がありますが、列挙はサービスが現在実際に適用している範囲の上位集合にすぎません。保護されるのは文書化された 7 種類だけで、アプリ保護ポリシーは明示的に除外されており、修復 (remediations) はリストにありません。
| リソース (プロファイル種類) | 承認のトリガー | 開始時期 (What’s new より) |
|---|---|---|
| アプリ | アプリ展開の作成、編集、削除、割り当て。アプリ保護ポリシーには適用されない。 | 2023 年 8 月 28 日の週に GA。2024 年 8 月 (2408) に Windows と非 Windows の範囲指定を追加 |
| スクリプト | Windows デバイスへの PowerShell スクリプトの展開 | Graph スキーマにおける最初の 2 つのポリシー種類 (app、script) の 1 つ |
| デバイス操作 | ワイプ、インベントリからの削除 (retire)、削除 | ワイプは 2025 年 8 月 18 日の週 (2508) に追加。retire と削除は概要ページに記載 |
| ロールベースのアクセス制御 | ロールに対するあらゆる変更: 権限、管理者グループ、メンバー グループの割り当て | 2025 年 8 月 18 日の週 (2508) |
| テナント構成 | デバイス カテゴリの作成、編集、削除 | 2025 年 9 月 15 日の週 (2509) |
| コンプライアンス ポリシー | コンプライアンス ポリシーの作成と管理 | 2026 年 3 月 2 日の週 (2602) |
| 構成ポリシー | 設定カタログで作成したポリシー | 2026 年 3 月 2 日の週 (2602) |
| アクセス ポリシー (MAA 自体) | 除外を含むアクセス ポリシーへのあらゆる変更 | 自動的に保護され、プロファイル種類として選択不可 |
この表について 2 点補足します。「保護対象リソースに対するすべての操作が保護され、編集、作成、変更、削除、割り当てを含みますがこれに限りません」は Microsoft の文言なので、既存アプリの割り当て変更も対象です。また、2026 年 6 月のアプリ専用 Graph 呼び出しへの適用はすべての行に一斉に効き、自動化について種類ごとにオプトインする仕組みはありません。
前提条件、ロール、ライセンス
Microsoft は MAA のワークフローに 3 つのロールを定義しています。この区別は自動化にとって重要で、サービス プリンシパルは 3 つ目のロールにしかなれません。
アクセス ポリシー管理者。 アクセス ポリシーを作成・管理します。Microsoft は、特権ロールである Intune Administrator の Entra ロールではなく、カスタム ロール リファレンスの Multi Admin Approval グループにある 4 つの権限 (Create access policy、Read access policy、Update access policy、Delete access policy) を持つカスタム Intune ロールを推奨しています。同グループの 5 つ目の権限 Approval for Multi Admin Approval は、2 人目の管理者が新規または変更後のアクセス ポリシーを承認するために必要なものです。
承認者。 次の 3 つをすべて満たす必要があります。アクセス ポリシーに割り当てられた承認者グループのメンバーであること、承認する種類のリソース固有の Read 権限を持つこと (たとえばデバイス削除の承認には ManagedDevices/Read)、そして承認者グループ自体が少なくとも 1 つの Intune ロール割り当てにメンバー グループとして追加されていること。グループがロールに割り当てられていない場合、Microsoft は「承認者グループのメンバーは定期的にグループから削除される」と述べており、私の経験では承認が突然機能しなくなる最大の原因です。グループはセキュリティ グループでなければならず (配布リスト、Microsoft 365 グループ、メールが有効なセキュリティ グループは「承認者メンバーシップの解決に静かに失敗」します)、入れ子のメンバーシップは「信頼性の低い動作を招く可能性がある」ため、メンバーは直接メンバーにします。
変更の要求者。 その操作に対する通常の Intune RBAC 権限 (MobileApps/Create、RemoteTasks/Wipe) が必要です。同じアカウントが要求を送信し、後で Complete を選択します。自動化ではこれがあなたのサービス プリンシパルであり、Microsoft は明確に述べています。「アプリケーションは MAA 要求を承認も拒否もできません。承認できるのは対話型の管理者アカウントだけです。」
グローバル管理者や Intune 管理者を含め、誰も自分の要求を承認できません。既定では参加する管理者全員に Intune ライセンスが必要です。Allow access to unlicensed admins 設定でこの要件を外せますが、Microsoft はこの設定が元に戻せないと警告しています。
Graph の権限
以下は beta のリファレンス ページに記載された権限です。MAA 固有のものはすべて beta にあり、v1.0 リファレンスには operationApprovalPolicy も operationApprovalRequest もありません。Microsoft の標準的な注記どおり、Intune の beta API はサポート対象ですが v1.0 より変更が頻繁です。
| 呼び出し | 文書化された権限 (委任とアプリケーション) |
|---|---|
operationApprovalPolicies の一覧、取得、作成、更新、削除 | DeviceManagementRBAC.Read.All、DeviceManagementRBAC.ReadWrite.All |
operationApprovalRequests の一覧または取得 | DeviceManagementConfiguration.Read.All、DeviceManagementConfiguration.ReadWrite.All、DeviceManagementRBAC.Read.All、DeviceManagementRBAC.ReadWrite.All |
approve、reject、cancelMyRequest、retrieveMyRequests、retrieveRequestStatus | DeviceManagementConfiguration.Read.All、DeviceManagementRBAC.Read.All |
deviceManagementScript の作成 (実例で使用) | DeviceManagementScripts.ReadWrite.All または DeviceManagementConfiguration.ReadWrite.All |
auditEvents の一覧 (v1.0) | DeviceManagementApps.Read.All、DeviceManagementApps.ReadWrite.All |
Graph の権限は必要条件であって十分条件ではありません。その上で Intune の RBAC チェックが動くため、DeviceManagementConfiguration.ReadWrite.All を持ちながら Intune ロールの割り当てがないアプリは、同じスコープを持つ委任された管理者とは異なる挙動を示します。
アクセス ポリシーの設計
ポリシーはいくつ必要か
各アクセス ポリシーは 1 つのプロファイル種類しかサポートしないため、アプリ、スクリプト、デバイス操作、RBAC、コンプライアンス ポリシー、構成ポリシーを保護したいテナントには最低 6 つのポリシーが必要です。私のパターンは、種類ごとに 1 ポリシーで 1 つのエンドポイント承認者グループを共有し、Role 種類だけは別ポリシーにして最後に作成するというものです。アプリ ポリシーをプラットフォームで分割する (2024 年 8 月のリリースでアプリ ポリシーを Windows アプリ、非 Windows アプリ、または両方に限定できるようになりました) のは、2 つの異なるチームが互いに承認し合う場合だけです。
承認者グループ
承認階層ごとに専用のセキュリティ グループを作成し、Intune ロール (リソースの Read 権限を持つカスタム ロールで十分) に直接割り当て、メンバーは直接メンバーに保ちます。監査ログが読みやすいように命名します。SG-Intune-MAA-Approvers-Endpoint、SG-Intune-MAA-Approvers-RBAC のように。要求は期限切れになるので、各グループに最低 2 人、フォロー ザ サンで運用しているなら異なるタイム ゾーンに承認者を置きます。
緊急時 (ブレークグラス) の考慮点
MAA には緊急バイパスのスイッチがなく、Intune は通知も送らないので、3 つの障害モードに備えます。
- 承認者が全員不在。 要求は 3 日で期限切れになります。対策はバイパスではなく、グループの人数とオンコールのローテーションです。
- Role のデッドロック。 Role のアクセス ポリシーは、承認者グループに必要なロール割り当てを含むすべての RBAC 変更を保護します。Microsoft が文書化した復旧手順は、Tenant administration > Multi Admin Approval > Access policies で Role ポリシーを削除し、3 から 5 分待ち、Tenant administration > Roles で割り当てを修正してからポリシーを再作成する、というものです。Role 種類を有効にする前に他のすべてのポリシーを構成し RBAC を検証しておけば回避できます。
- 待てない自動化。 Exclusions タブで特定のエンタープライズ アプリケーションを 1 つのポリシーから除外します。除外はアプリ専用トークンにのみ適用され (同じアプリの委任呼び出しは引き続き傍受されます)、アクセス ポリシーあたり 50 アプリケーションが上限で、2 人目の管理者の承認が必要で、追加、削除、変更はすべて監査ログに記録されます。Microsoft の警告は率直です。各除外は「承認ワークフローに隙間を作り、除外されたアプリケーションが侵害された場合に悪用される可能性があります」。
私の除外ルールは、変更できないベンダー製ツールだけ、必要な 1 ポリシーだけに限定、クライアント シークレットではなく証明書資格情報、そして既知の IP 範囲の外からサービス プリンシパルをブロックするワークロード ID の条件付きアクセス ポリシー、です。このポリシーには Workload Identities Premium のライセンスが必要で、自テナントに登録された単一テナントのサービス プリンシパルしか対象になりませんが、承認なしでデバイスをワイプできるアプリに対してはライセンス料に見合う価値があります。
ポリシーの作成
管理センターでは、Tenant administration > Multi Admin Approval > Access policies > Create です。Basics で名前と単一の Profile type を設定し、Approvers で Add groups を選び、Exclusions で必要なら Add enterprise applications を選び、Review + submit for approval で Business justification を入力して Submit for approval を選択します。Approval for Multi Admin Approval を持つ 2 人目の管理者が承認し、最初の管理者がポリシーに戻って Complete を選択します。
Graph では 1 回の POST です。アクセス ポリシー自体が保護対象なので、この呼び出しにも後述する承認フローが発生すると想定してください。
POST https://graph.microsoft.com/beta/deviceManagement/operationApprovalPolicies
Content-Type: application/json
{
"@odata.type": "#microsoft.graph.operationApprovalPolicy",
"displayName": "MAA - Windows scripts",
"description": "Second-admin approval for PowerShell script deployments",
"policyType": "script",
"policyPlatform": "notApplicable",
"policySet": {
"@odata.type": "microsoft.graph.operationApprovalPolicySet",
"policyType": "script",
"policyPlatform": "notApplicable"
},
"approverGroupIds": [ "<approver security group object ID>" ]
}GET https://graph.microsoft.com/beta/deviceManagement/operationApprovalPolicies で既存のポリシーを一覧できます。displayName は 128 文字、description は 1024 文字が上限です。
人間の管理者の承認ワークフロー
送信
要求者は通常の作成または編集フローを使います。保存前の最終ページに Business justification フィールドが表示されます。承認者が読むのはこれなので、しっかり記入して送信します。同じオブジェクトに対する要求が既に保留中なら、Intune はメッセージを出して新しい要求をブロックします。状態は Tenant administration > Multi Admin Approval > My requests で確認でき、保留中の要求は同じ場所で Cancel request により取り下げられます。
承認または拒否
承認者は Tenant administration > Multi Admin Approval > Received requests (概要ではこの一覧を All requests とも呼んでいます) か、統合された Tenant administration > Admin tasks ペインに移動します。後者は MAA 要求を Defender のセキュリティ タスクや Endpoint Privilege Management の昇格要求と並べて表示し、開くには Organization > Read が必要です。Business justification リンクを選択して変更内容を読み、Approver notes を入力し、Approve request または Reject request を選びます。メモは要求者の My requests ビューに返されるので、拒否理由はこれで伝わります。2026 年 4 月 27 日の週 (サービス リリース 2604) 以降、Change Review Agent の提案がある場合は My requests と All requests タブに Windows PowerShell スクリプト要求向けの Agent Response 列も表示されます。この統合はプレビューです。
完了
承認しても変更は適用されません。元の要求者が要求を開いて Complete を選択すると、Intune が処理し、状態が Completed になり、コンソール通知が成功または失敗を知らせます。自動化ではこのステップを承認コード付きの再送として再現します。
ライフサイクルと期限切れ
| 管理センターの状態 | Graph の status 値 | 意味 |
|---|---|---|
| Needs approval | needsApproval | 承認者を待っている |
| Approved | approved | 承認済み。要求者の Complete を待っている |
| Completed | completed | 変更が適用された |
| Rejected | rejected | 承認者が拒否。まだ必要なら新しい要求を送る |
| Canceled | cancelled | 要求者が取り下げた |
| Expired | expired | 3 日以内に処理が進まなかった。再送が必要 |
Microsoft の文言はこうです。「要求が 3 日以内にさらに処理されない場合、Expired になり、再送信する必要があります。各状態の変化は、変化後最大 30 日間表示されます。」各要求には expirationDateTime もあり、自動化では 72 時間を固定値にせずこの値を監視すべきです。
自動化: Graph API のワークフロー
エンドポイントと API バージョン
以下はすべて beta エンドポイントです。現時点で v1.0 の同等物はないので、コードはこれらの URL に固定し、移行の日に備えて Intune What’s New シリーズを追ってください。
| 目的 | 要求 |
|---|---|
| アクセス ポリシーの一覧 | GET /beta/deviceManagement/operationApprovalPolicies |
| アクセス ポリシーの作成 | POST /beta/deviceManagement/operationApprovalPolicies |
| 承認要求の一覧 | GET /beta/deviceManagement/operationApprovalRequests |
| 1 件の要求を取得 | GET /beta/deviceManagement/operationApprovalRequests/{id} |
| 自分の要求 | GET /beta/deviceManagement/operationApprovalRequests/retrieveMyRequests |
| オブジェクトが保留中の要求でロックされているか | POST /beta/deviceManagement/operationApprovalRequests/retrieveRequestStatus に entityId と entityType を付ける |
| 承認 | POST /beta/deviceManagement/operationApprovalRequests/{id}/approve |
| 拒否 | POST /beta/deviceManagement/operationApprovalRequests/{id}/reject |
| 自分の要求を取り消す | POST /beta/deviceManagement/operationApprovalRequests/cancelMyRequest に { "id": "..." } を付ける |
| 監査証跡 | GET /v1.0/deviceManagement/auditEvents |
アプリ専用と委任の違い
承認プロトコルはどちらのトークン種類でも同一で、ヘッダーも状態コードも変わりません。変わるのは誰が何をできるかです。
- アプリ専用 (クライアント資格情報) のプリンシパルは、保護対象の変更を送信し、要求状態を読み取り、承認コードで再送し、ポリシーから除外されることができます。承認や拒否はできず、作成した要求には
requestor.applicationにアプリが記録されます。 - 委任トークンはサインインした管理者として振る舞います。送信と読み取りができ、その管理者が承認者グループに属しリソースの Read 権限を持っていれば、他人の要求を承認または拒否できます。自分の要求は決して承認できず、アプリが除外されていても委任呼び出しには除外が適用されません。
設計上の結論はこうです。パイプラインの ID が送信し、人間が承認し (ポータルで、または本人がサインインしたセッションからの委任 Graph 呼び出しで)、パイプラインの ID が完了させる。「承認者」として 2 つ目のサービス プリンシパルを作らないでください。Microsoft はそれが機能しないと述べており、目的そのものに反します。
ステップ 1: 理由ヘッダーを付けて送信する
変更要求に x-msft-approval-justification を追加します。値は Base64 でエンコードする必要があり、Microsoft の例の値 YXBwIG9ubHkgdGVzdA== は app only test にデコードされます。以下のサンプルは Windows PowerShell スクリプトを作成し、そのヘッダーは CHG0012345: deploy pilot script to Ring 0 にデコードされます。
POST https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts
Content-Type: application/json
x-msft-approval-justification: Q0hHMDAxMjM0NTogZGVwbG95IHBpbG90IHNjcmlwdCB0byBSaW5nIDA=
{
"@odata.type": "#microsoft.graph.deviceManagementScript",
"displayName": "BHG - Pilot script",
"description": "Created by automation under Multi Admin Approval",
"scriptContent": "V3JpdGUtT3V0cHV0ICJIZWxsbyBXb3JsZCI=",
"runAsAccount": "system",
"enforceSignatureCheck": false,
"fileName": "Pilot.ps1",
"runAs32Bit": false,
"roleScopeTagIds": ["0"]
}ヘッダーがないと、呼び出しは x-msft-approval-justification ヘッダーが必須であるというエラーで失敗します。ハウツーではこれを HTTP 400 と説明しています。
ステップ 2: 412 を読み取り、承認コードを保持する
ほとんどのスクリプトがここで壊れます。送信が成功しても 201 Created は返りません。返るのは外側の Graph エラー コードが BadRequest の HTTP 412 Precondition Failed で、応答には x-msft-approval-code ヘッダーが付きます。Microsoft のガイダンスはこうです。「このヘッダーの存在と HTTP 412 を合わせて、MAA が要求を受け付けて承認要求を作成した合図として使用してください。」メソッド、URL、本文、コードを保存してください。後で 4 つすべてが必要になります。
HTTP/1.1 412 Precondition Failed
x-msft-approval-code: aabb1234-5678-9012-abcd-ef0123456789
Content-Type: application/json
{
"error": {
"code": "BadRequest",
"message": "{ \"Message\": \"Approval Required. Request Approval using the request ID returned as part of the x-msft-approval-code response header. x-msft-approval-code: aabb1234-5678-9012-abcd-ef0123456789 ...\" }"
}
}ステップ 3: 待機、ポーリング、通知
Intune は誰にも通知しないので、スクリプトがその役目を担います。承認コードは要求 ID なので、要求を直接読むか、Microsoft がハウツーで示しているフィルター形式を使います。業務上の理由と Tenant administration > Multi Admin Approval への案内を、承認者が実際に見る場所に投稿し、expirationDateTime を使っていつエスカレーションするかを決めます。
GET https://graph.microsoft.com/beta/deviceManagement/operationApprovalRequests/aabb1234-5678-9012-abcd-ef0123456789GET https://graph.microsoft.com/beta/deviceManagement/operationApprovalRequests?$filter=requestId eq 'aabb1234-5678-9012-abcd-ef0123456789'送信する前に、retrieveRequestStatus を使えば対象オブジェクトが他人の保留中の要求でロックされているか (entityLocked: true) が分かるので、「既に保留中」のエラーに当たる代わりに早期に失敗させられます。
ステップ 4: Graph 経由で承認する
人間の承認者は、ポータルの代わりに委任トークンで Graph から操作できます。justification は 1024 文字が上限で、approvalSource は省略可能で既定値は unknown です。
POST https://graph.microsoft.com/beta/deviceManagement/operationApprovalRequests/aabb1234-5678-9012-abcd-ef0123456789/approve
Content-Type: application/json
{
"justification": "Approved per CHG0012345 after reviewing the script content in the request pane",
"approvalSource": "adminConsole"
}拒否は /reject に対して同じ形です。どちらも文字列の本文を持つ 200 OK を返します。これらのアクションの権限表にはアプリケーション権限が載っていますが、ハウツーはアプリケーションが承認も拒否もできないと断言しているので、委任経路だけが機能するものとして扱ってください。
ステップ 5: 承認コードを付けて再送する
status が approved になったら、理由ヘッダーを x-msft-approval-code に置き換えて同一の要求を再送します。これは要求者が Complete を選択することの API 版で、通常の 201 Created と新しいオブジェクトが返ります。
POST https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts
Content-Type: application/json
x-msft-approval-code: aabb1234-5678-9012-abcd-ef0123456789
{ ...the same body as Step 1... }PowerShell による完全な実例
Microsoft Graph PowerShell SDK の Connect-MgGraph と Invoke-MgGraphRequest を使います。Microsoft.Graph.Beta.DeviceManagement.Administration のリファレンスに操作承認エンドポイント専用のコマンドレットは見つからず、Invoke-MgGraphRequest は「同等のコマンドレットがまだない API」のために Microsoft が文書化している経路です。-SkipHttpErrorCheck で 412 が例外にならず、-ResponseHeadersVariable と -StatusCodeVariable でヘッダーと状態コードを取得します。
最初のスクリプトは証明書でアプリ専用接続し、Windows PowerShell スクリプトを送信し、承認を待ち、完了させます。
#Requires -Modules Microsoft.Graph.Authentication
<#
Submit-IntuneScriptWithMaa.ps1
App-only automation that creates a Windows PowerShell script in Intune under Multi Admin Approval.
The app registration needs DeviceManagementScripts.ReadWrite.All (create the script) and
DeviceManagementConfiguration.Read.All or DeviceManagementRBAC.Read.All (read approval requests).
#>
param(
[Parameter(Mandatory)] [string] $TenantId,
[Parameter(Mandatory)] [string] $ClientId,
[Parameter(Mandatory)] [string] $CertificateThumbprint,
[string] $Justification = "CHG0012345: deploy pilot script to Ring 0",
[int] $PollIntervalSeconds = 300
)
Connect-MgGraph -ClientId $ClientId -TenantId $TenantId -CertificateThumbprint $CertificateThumbprint -NoWelcome
$uri = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts"
$scriptText = 'Write-Output "Hello from Intune"'
$body = @{
"@odata.type" = "#microsoft.graph.deviceManagementScript"
displayName = "BHG - Pilot script"
description = "Created by automation under Multi Admin Approval"
scriptContent = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($scriptText))
runAsAccount = "system"
enforceSignatureCheck = $false
fileName = "Pilot.ps1"
runAs32Bit = $false
roleScopeTagIds = @("0")
} | ConvertTo-Json -Depth 5
# Step 1: submit with the Base64 justification header. Expect HTTP 412 plus x-msft-approval-code.
$encodedJustification = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Justification))
$null = Invoke-MgGraphRequest -Method POST -Uri $uri -Body $body -ContentType "application/json" `
-Headers @{ "x-msft-approval-justification" = $encodedJustification } `
-SkipHttpErrorCheck -ResponseHeadersVariable responseHeaders -StatusCodeVariable statusCode
if ($statusCode -eq 201) {
Write-Output "Created immediately: scripts are not MAA-protected in this tenant, or this app is excluded."
return
}
# Step 2: the 412 is the success signal. Pull the approval code out of the response headers.
$codeKey = $responseHeaders.Keys | Where-Object { $_ -ieq "x-msft-approval-code" } | Select-Object -First 1
if ($statusCode -ne 412 -or -not $codeKey) {
throw "Unexpected HTTP $statusCode without an approval code. Check Graph permissions and Intune RBAC."
}
$approvalCode = @($responseHeaders[$codeKey])[0]
Write-Output "Approval request $approvalCode created. Waiting for a second administrator."
# Step 3: notify your approvers here (ticket, chat, email). Intune sends nothing on its own.
# Then poll the request by ID until it leaves needsApproval. The service expires it after 3 days.
$requestUri = "https://graph.microsoft.com/beta/deviceManagement/operationApprovalRequests/$approvalCode"
do {
Start-Sleep -Seconds $PollIntervalSeconds
$request = Invoke-MgGraphRequest -Method GET -Uri $requestUri
Write-Output ("{0:u} status={1} expires={2}" -f (Get-Date), $request.status, $request.expirationDateTime)
} while ($request.status -eq "needsApproval")
if ($request.status -ne "approved") {
throw "Request $approvalCode ended as '$($request.status)'. Approver notes: $($request.approvalJustification)"
}
# Step 5: replay the identical request with the approval code. This is the API form of 'Complete'.
$created = Invoke-MgGraphRequest -Method POST -Uri $uri -Body $body -ContentType "application/json" `
-Headers @{ "x-msft-approval-code" = $approvalCode }
Write-Output "Script created with id $($created.id). Approved by $($request.approver.user.displayName)."承認者側は、承認者グループのメンバーとしてサインインして対話的に実行します。待機中の要求を一覧し、誰が何のために要求したかを表示し、承認者が管理センターで変更内容を読んだ後に 1 件を承認します。
# Approve-IntuneMaaRequests.ps1 - delegated session for a human approver
Connect-MgGraph -Scopes "DeviceManagementRBAC.Read.All" -NoWelcome
$all = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/operationApprovalRequests"
$pending = @($all.value | Where-Object { $_.status -eq "needsApproval" })
foreach ($r in $pending) {
$who = if ($r.requestor.application.displayName) { $r.requestor.application.displayName } else { $r.requestor.user.displayName }
Write-Output "$($r.id) from $who types=$($r.requiredOperationApprovalPolicyTypes -join ',') expires $($r.expirationDateTime)"
Write-Output " justification: $($r.requestJustification)"
}
$id = Read-Host "Request ID to approve"
$decision = @{
justification = "Approved per CHG0012345 after reviewing the script content in the admin center"
approvalSource = "adminConsole"
} | ConvertTo-Json
Invoke-MgGraphRequest -Method POST -Body $decision -ContentType "application/json" `
-Uri "https://graph.microsoft.com/beta/deviceManagement/operationApprovalRequests/$id/approve"スクリプト オブジェクトができたら割り当てを行い、テスト デバイスで Intune ポリシーの同期を強制して着地を確認します。割り当ても保護対象リソースの変更なので、グループを追加する際にはもう一度 412 の往復があると想定してください。
Win32 アプリの更新を毎晩公開する Azure Automation の Runbook をこのパターンに移すなら、最初の 1 週間で 2 つのことに気付くはずです。Runbook にはサンドボックスを何時間も占有しないよう、承認コードをキーにした別の再開ジョブが必要になること、そして承認者は理由の先頭に変更内容の説明ではなく変更チケット番号を求めるということです。彼らが実際に開くのはチケットだからです。
運用ガイダンス
SLA、期限切れ、通知
社内の承認 SLA は 3 日の期限より十分内側に設定します。私の基準はアプリとスクリプトで 4 営業時間、デバイス操作と RBAC 変更で 1 時間とし、チケット システムにオンコールの承認者を明記します。Intune は通知を送らないので、通知機能は送信スクリプト側に置き、retrieveMyRequests または一覧エンドポイントを呼び出して needsApproval のまま expirationDateTime まで 24 時間を切ったものをエスカレーションするスケジュール ジョブで補います。30 日の表示期間も忘れないでください。それを過ぎると要求はコンソールから消えるので、証跡として必要なものはエクスポートしておきます。
監査とレポート
Graph のハウツーは、MAA のイベントが「承認、ブロック、通過、除外の追加、除外の削除を含めて」既存の Intune 監査ログに記録されると確認しています。管理センターでは Tenant administration > Audit logs にあり、Add filters > Category と Activity で絞り込めます。Export は CSV を書き出し、同じペインからコンソールの表示期間を超えて保持するために Azure Monitor へログをルーティングできます。監査ログのドキュメントによれば、閲覧には Intune Administrator ロールか Audit data > Read を持つ Intune ロールが必要です。プログラムからは GET https://graph.microsoft.com/v1.0/deviceManagement/auditEvents が 2 年分のイベントを返し、各イベントの actor ブロックには applicationId、servicePrincipalName、userPrincipalName が含まれるので、レポートで自動化による承認と人間の承認を分けられます。
よくあるエラー
| 症状 | 考えられる原因 | 対処 |
|---|---|---|
HTTP 400 と x-msft-approval-justification が必須というメッセージ | 保護対象リソースでヘッダーがない | Base64 ヘッダーを付けて再送 |
HTTP 412 Precondition Failed、コード BadRequest、x-msft-approval-code ヘッダーあり | 想定どおり。承認要求が作成された | コードを保存し、ポーリングし、通知し、再送 |
| HTTP 403 Forbidden | 要求者の Graph 権限または Intune RBAC の不足。Microsoft の 2026 年 6 月の発表も MAA のブロックを 403 と説明 | アプリの権限とロール割り当てを確認し、次に除外を確認 |
「このオブジェクトの要求は既に保留中」または entityLocked: true | 同じオブジェクトに別の要求が開いている | 待つか、その要求者に取り消してもらう |
状態が expired | 3 日以内に誰も処理しなかった | 理由ヘッダーを付けて再送。新しいコードが発行される |
| 承認者が要求を見られない、または承認できない | グループが Intune ロールに未割り当て、セキュリティ グループでない、入れ子のメンバーシップ、リソースの Read 権限がない | 前提条件に沿ってグループを修正 |
| 自分の要求の承認が失敗する | 仕様上許可されない | 別の管理者が承認 |
| Role ポリシー有効化後に RBAC 変更がブロックされる | Role のデッドロック | Role ポリシーを削除し、3 から 5 分待ち、RBAC を修正し、再作成 |
| 承認コード付きの再送が失敗する | 元の要求と異なる、または期限が過ぎた | Microsoft は同じ要求を再送せよと述べている。変更せず速やかに再送 |
対応チェックリスト
- Tenant administration > Multi Admin Approval > Access policies を開き、有効なポリシーを一覧します。1 つもなければ API への適用はまだ関係なく、受け身で引き継ぐのではなく意図的に設計する好機です。
- Entra ID > Enterprise apps で Intune の書き込み権限を持つサービス プリンシパルをすべて棚卸しし、それぞれが触れる保護対象種類 (アプリ、スクリプト、デバイス操作、RBAC、コンプライアンス、構成、デバイス カテゴリ) に対応付けます。
- まず承認者グループを整えます。セキュリティ グループのみ、直接メンバー、各グループ最低 2 人、各グループをリソースの Read 権限を持つ Intune ロールに直接割り当てます。
- プロファイル種類ごとに 1 つのアクセス ポリシーを作成します。デッドロックを避けるため、Role 種類は他を検証し終えるまで後回しにします。
- 保護対象種類を変更するスクリプトと Runbook をすべて更新します。
x-msft-approval-justification(Base64) を送り、x-msft-approval-code付きの HTTP 412 を成功として扱い、メソッド、URL、本文、コードを永続化し、operationApprovalRequests/{id}をポーリングし、承認者に通知し、x-msft-approval-codeを付けて再送します。 - 除外は意図的に決めます。変更できないベンダー製ツールだけ、1 つずつ 1 ポリシーに限定、証明書資格情報、ワークロード ID の条件付きアクセス ポリシー、そしてリストの四半期ごとの見直しです。
- 承認 SLA を文書化し、承認者をオンコールに置き、上記の委任 PowerShell または Admin tasks ペインを承認者に渡します。
- Intune の監査ログを Azure Monitor にルーティングし、MAA の承認、ブロック、通過イベントを
actor.applicationIdとactor.userPrincipalNameで分けるレポートを 1 つ作ります。 - フロー全体を一度パイロットします。412 の往復でスクリプトを作成し、割り当て、テスト デバイスで同期を強制し、監査エントリが監査人の期待どおりに読めることを確認します。
- コードを beta の URL に固定し、v1.0 への移行や新しい保護対象種類について Intune What’s New シリーズを追います。列挙は既に Microsoft の向かう先を示しています。
もう一組の手が必要ですか? Big Hat Group は米国とカナダの組織に、2 週間のヘルス チェックから完全な移行まで Microsoft Intune コンサルティングを提供しています。ディスカバリー コールを予約して、お客様の環境についてお話しください。
参考資料
- Use Multi Admin Approval in Intune - Microsoft Intune
- Use Multi Admin Approval with the Microsoft Graph API - Microsoft Intune
- What’s new in Microsoft Intune (2026 年 4 月 27 日と 6 月 22 日の週)
- What’s new in Microsoft Intune archive (2023 年 8 月、2024 年 8 月、2025 年 8 月と 9 月、2026 年 3 月の項目)
- Create a custom role in Intune - Microsoft Intune
- Centrally manage Admin Tasks - Microsoft Intune
- Audit changes and events in Microsoft Intune - Microsoft Intune
- operationApprovalPolicy resource type - Microsoft Graph beta
- Create operationApprovalPolicy - Microsoft Graph beta
- List operationApprovalPolicies - Microsoft Graph beta
- operationApprovalRequest resource type - Microsoft Graph beta
- List operationApprovalRequests - Microsoft Graph beta
- Get operationApprovalRequest - Microsoft Graph beta
- approve action - Microsoft Graph beta
- reject action - Microsoft Graph beta
- cancelMyRequest action - Microsoft Graph beta
- retrieveMyRequests function - Microsoft Graph beta
- retrieveRequestStatus action - Microsoft Graph beta
- operationApprovalRequestEntityStatus resource type - Microsoft Graph beta
- Create deviceManagementScript - Microsoft Graph beta
- List auditEvents - Microsoft Graph v1.0
- Connect-MgGraph (Microsoft.Graph.Authentication)
- Invoke-MgGraphRequest (Microsoft.Graph.Authentication)
- Microsoft Entra Conditional Access for workload identities