當我在 6 月發布那篇多重管理員核准現在也對透過 Graph API 的自動化強制執行的短訊之後,它成了本站閱讀量最高的頁面之一,而後續收到的郵件都在問同一件事:不是「改了什麼」,而是「要怎麼用指令碼實作」。本文就是那份完整的實作演練。它涵蓋截至 2026 年 10 月多重管理員核准 (MAA) 保護的內容、如何設計存取原則與核准者群組而不把自己鎖在門外、人工核准者在管理中心的確切點選路徑,以及多數讀者真正想看的部分:一個建立受保護物件的指令碼如何收到核准要求、如何等待、核准者如何透過 Graph 核准、指令碼又如何完成剩下的工作。這裡的每個端點、標頭、權限與限制都已對照 Microsoft Learn 查證。凡是加入我個人意見的地方,我都會明說。

多重管理員核准是什麼,為什麼現在也涵蓋 Graph 自動化

根據 Microsoft Learn 概觀,MAA 存取原則「要求第二個系統管理帳戶在變更套用之前核准該變更」。一條存取原則指定一種受保護的設定檔類型,以及允許核准該類型變更的帳戶群組。當任何帳戶變更受保護資源時,Intune 會保留該變更,直到另一個帳戶明確核准;核准者也可以拒絕。業務理由、核准者附註與決定都會記入 Intune 稽核記錄。

在 2026 年 6 月之前,只有互動式(委派)管理員動作會被攔截。如果服務主體以僅限應用程式權杖執行同樣的抹除或指令碼部署,會直接放行。Microsoft 在 2026 年 6 月 22 日當週的 What’s new 項目補上了這個缺口:「多重管理員核准 (MAA) 現在適用於自動化透過 Microsoft Graph API 發出的 API 呼叫,而不只是互動式管理員動作。」隨之而來有兩道護欄。對 API 呼叫的強制執行只適用於已經設定 MAA 存取原則的租用戶,它不會在任何地方自動啟用 MAA。另外,根據 Graph API 操作指南,「MAA 只適用於修改受保護資源的作業(POST、PATCH、PUT、DELETE)。唯讀作業 (GET) 不受影響。」

至於 Microsoft 為什麼這麼做,只要站在攻擊者的角度想一想就明白了。一個持有 DeviceManagementManagedDevices.ReadWrite.All 的應用程式,其用戶端密碼一旦外洩,過去就等於一顆涵蓋整個租用戶的抹除按鈕。現在同樣的呼叫只會產生一個核准要求,必須有人讀過之後才會發生任何事。

受保護的資源

概觀頁面列出了七種資源類型。Graph 的 operationApprovalPolicyType 列舉包含更多值(autopilot、windows365、endpointPrivilegeManagement、filter、appProtectionPolicy 等),但列舉只是服務目前實際強制範圍的超集。只有文件記載的這七種受保護,應用程式保護原則被明確排除,而修復 (remediations) 不在清單中。

資源(設定檔類型)觸發核准的動作自何時起(依據 What’s new)
應用程式應用程式部署:建立、編輯、刪除、指派。不適用於應用程式保護原則。2023 年 8 月 28 日當週正式推出;2024 年 8 月 (2408) 新增 Windows 與非 Windows 的範圍劃分
指令碼向 Windows 裝置部署 PowerShell 指令碼Graph 結構描述中最初的兩種原則類型之一(app、script)
裝置動作抹除、淘汰與刪除抹除於 2025 年 8 月 18 日當週 (2508) 加入;淘汰與刪除列於概觀頁面
以角色為基礎的存取控制對角色的任何變更:權限、管理員群組、成員群組指派2025 年 8 月 18 日當週 (2508)
租用戶設定裝置類別:建立、編輯、刪除2025 年 9 月 15 日當週 (2509)
合規性原則建立與管理合規性原則2026 年 3 月 2 日當週 (2602)
設定原則透過設定目錄建立的原則2026 年 3 月 2 日當週 (2602)
存取原則(MAA 本身)對存取原則的任何變更,包括其排除項目自動受保護;無法作為設定檔類型選取

關於這張表有兩點說明。「受保護資源的所有動作都受保護,包括但不限於:編輯、建立、修改、刪除、指派」是 Microsoft 的原文,所以對現有應用程式的指派變更也算在內。另外,2026 年 6 月對僅限應用程式 Graph 呼叫的強制執行同時適用於每一列;自動化沒有按類型個別選擇加入的選項。

先決條件、角色與授權

Microsoft 在 MAA 工作流程中描述了三種角色,這個區分對自動化很重要,因為服務主體只可能是第三種。

存取原則管理者。 建立與管理存取原則。Microsoft 建議使用自訂 Intune 角色,包含自訂角色參考中 Multi Admin Approval 群組的四項權限(Create access policy、Read access policy、Update access policy、Delete access policy),而不是使用特權等級的 Intune Administrator Entra 角色。該群組的第五項權限 Approval for Multi Admin Approval,是第二位管理員核准新建或變更的存取原則時所需要的。

核准者。 必須同時滿足三個條件:是指派給該存取原則的核准者群組成員;擁有所核准類型的資源層級 Read 權限(例如核准裝置刪除需要 ManagedDevices/Read);而且核准者群組本身必須作為成員群組加入至少一個 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 變動更頻繁。

呼叫文件記載的權限(委派與應用程式)
列出、取得、建立、更新、刪除 operationApprovalPoliciesDeviceManagementRBAC.Read.All、DeviceManagementRBAC.ReadWrite.All
列出或取得 operationApprovalRequestsDeviceManagementConfiguration.Read.All、DeviceManagementConfiguration.ReadWrite.All、DeviceManagementRBAC.Read.All、DeviceManagementRBAC.ReadWrite.All
approve、reject、cancelMyRequest、retrieveMyRequests、retrieveRequestStatusDeviceManagementConfiguration.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 角色指派的應用程式,與擁有相同範圍的委派管理員表現並不相同。

設計存取原則

需要多少條原則

每條存取原則只支援一種設定檔類型,所以一個想要保護應用程式、指令碼、裝置動作、RBAC、合規性與設定原則的租用戶至少需要六條原則。我的做法是每種類型一條原則、共用一個端點核准者群組,再加一條單獨的 Role 類型原則,留到最後建立。只有在兩個不同團隊互相核准時,我才會依平台拆分應用程式原則(2024 年 8 月的版本允許把應用程式原則限定為 Windows 應用程式、非 Windows 應用程式或兩者)。

核准者群組

為每個核准層級建立一個專用安全性群組,直接指派到一個 Intune 角色(帶有資源層級 Read 權限的自訂角色就足夠),並讓成員保持為直接成員。命名時讓稽核記錄容易閱讀:SG-Intune-MAA-Approvers-Endpoint、SG-Intune-MAA-Approvers-RBAC。每個群組至少放兩名核准者,若你採用追著太陽跑的輪班模式,就讓他們分布在不同時區,因為要求會到期。

緊急存取的考量

MAA 沒有緊急略過開關,Intune 也不會送出通知,所以要為三種故障模式做好準備。

  1. 所有核准者都不在。 要求會在 3 天後到期。因應方式是擴大群組規模並安排值班輪替,而不是略過。
  2. Role 死結。 Role 存取原則保護所有 RBAC 變更,包括核准者群組所需的角色指派。Microsoft 記載的復原步驟是:在 Tenant administration > Multi Admin Approval > Access policies 下刪除 Role 原則,等待 3 到 5 分鐘,在 Tenant administration > Roles 下修正指派,然後重新建立原則。避免方法是在啟用 Role 類型之前先設定好其他所有原則並驗證 RBAC。
  3. 無法等待的自動化。 使用 Exclusions 索引標籤把某個企業應用程式從一條原則中排除。排除項目只對僅限應用程式權杖有效(同一應用程式的委派呼叫仍會被攔截),每條存取原則最多 50 個應用程式,需要第二位管理員核准,而且每次新增、移除或修改都會記入稽核記錄。Microsoft 的警告很直白:每個排除項目「都會在核准工作流程中製造一個缺口,一旦被排除的應用程式遭到入侵,就可能被利用」。

我對排除項目的規則是:只用於我無法修改的廠商工具,只限定到它需要的那一條原則,以憑證認證取代用戶端密碼,並設定一條工作負載身分識別的條件式存取原則來阻擋該服務主體從已知 IP 範圍以外存取。該原則需要 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 權限的管理員核准後,第一位管理員回到該原則並選取 Complete。

透過 Graph 則是一個 POST。因為存取原則本身也受保護,這個呼叫同樣會經歷下文描述的核准流程。

http
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 approvalneedsApproval等待核准者
Approvedapproved已核准;等待要求者執行 Complete
Completedcompleted變更已套用
Rejectedrejected被核准者拒絕;若仍需要請提交新要求
Canceledcancelled由要求者撤回
Expiredexpired3 天內未被進一步處理;必須重新提交

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
取得單一要求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 權限時,可以核准或拒絕他人的要求。它永遠不能核准自己的要求,而且即使應用程式被排除,排除項目也不適用於委派呼叫。

由此得到的設計結論是:你的管線身分負責提交,人工負責核准(在入口網站中,或從本人登入的工作階段發出委派 Graph 呼叫),再由管線身分完成。不要再建第二個服務主體充當「核准者」;Microsoft 說這行不通,而且也違背了初衷。

第 1 步:帶著理由標頭提交

在修改要求上加上 x-msft-approval-justification。該值必須經過 Base64 編碼;Microsoft 的範例值 YXBwIG9ubHkgdGVzdA== 解碼後是 app only test。下面的範例建立一個 Windows PowerShell 指令碼,其標頭解碼後為 CHG0012345: deploy pilot script to Ring 0。

http
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,而是回傳 HTTP 412 Precondition Failed,外層 Graph 錯誤碼為 BadRequest,回應中帶有 x-msft-approval-code 標頭。Microsoft 的指引是:「把這個標頭的存在加上 HTTP 412 一起視為 MAA 已接受要求並建立核准要求的訊號。」請保存方法、URL、本文與這個代碼;稍後四樣都要用到。

http
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 決定何時升級處理。

http
GET https://graph.microsoft.com/beta/deviceManagement/operationApprovalRequests/aabb1234-5678-9012-abcd-ef0123456789
http
GET 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。

http
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 取代理由標頭,原樣重送同一個要求。這相當於要求者在 API 層面選取 Complete,會回傳正常的 201 Created 與新物件。

http
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 參考中找不到作業核准端點的專用 cmdlet,而 Invoke-MgGraphRequest 正是 Microsoft 記載的、用於「尚無對應 cmdlet 的 API」的途徑。-SkipHttpErrorCheck 讓 412 不會擲回例外,-ResponseHeadersVariable 與 -StatusCodeVariable 則擷取標頭與狀態碼。

第一個指令碼以憑證用僅限應用程式方式連線,提交一個 Windows PowerShell 指令碼,等待核准,然後完成。

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)."

核准者這一半以互動方式執行,由核准者群組成員登入操作。它會列出等待中的要求,顯示是誰提出以及理由,並在核准者已在管理中心讀過變更之後核准其中一條。

powershell
# 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 搬到這個模式,第一週可以預期兩點收穫。Runbook 需要一個以核准碼為鍵值的獨立恢復工作,這樣它就不必讓沙箱空等好幾個小時;核准者則會希望理由以變更單號開頭,而不是描述變更本身,因為變更單才是他們真正會打開的東西。

營運指南

SLA、到期與通知

把內部核准 SLA 設定在 3 天到期期限之內並留足餘裕。我的做法是應用程式與指令碼四個工作小時,裝置動作與 RBAC 變更一小時,並在工單系統中指定一名值班核准者。由於 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 會回傳兩年的事件;每個事件的 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同一物件已有另一條開啟中的要求等待它結束,或請其要求者取消
狀態為 expired3 天內無人處理帶理由標頭重新提交;會得到新的代碼
核准者看不到或無法核准要求群組未指派到 Intune 角色、不是安全性群組、巢狀成員資格,或缺少資源層級 Read 權限依先決條件清單修正該群組
核准自己的要求失敗設計上不允許由另一位管理員核准
啟用 Role 原則後 RBAC 變更被封鎖Role 死結刪除 Role 原則,等待 3 到 5 分鐘,修正 RBAC,再重新建立
帶核准碼重新提交失敗要求與原始要求不同,或時間視窗已過Microsoft 說要重新提交同一個要求;請原樣且及時重送

應該怎麼做

  1. 開啟 Tenant administration > Multi Admin Approval > Access policies,列出使用中的原則。如果一條都沒有,API 強制執行暫時與你無關,這正是有計畫地設計它、而不是被動繼承的時機。
  2. 在 Entra ID > Enterprise apps 下清點所有擁有 Intune 寫入權限的服務主體,並把每一個對應到它觸及的受保護類型(應用程式、指令碼、裝置動作、RBAC、合規性、設定、裝置類別)。
  3. 先修好核准者群組:只用安全性群組、直接成員、每組至少兩人,每個群組都直接指派到一個帶有資源層級 Read 權限的 Intune 角色。
  4. 為每種設定檔類型建立一條存取原則。Role 類型留到其他類型驗證完成之後,以避免死結。
  5. 更新所有修改受保護類型的指令碼與 Runbook:送出 x-msft-approval-justification(Base64),把帶 x-msft-approval-code 的 HTTP 412 當作成功,保存方法、URL、本文與代碼,輪詢 operationApprovalRequests/{id},通知核准者,再以 x-msft-approval-code 重送。
  6. 有意識地決定排除項目:只用於無法修改的廠商工具,每個只對應一條原則,使用憑證認證,設定工作負載身分識別的條件式存取原則,並每季複核清單。
  7. 把核准 SLA 寫下來,安排核准者值班,並把上面的委派 PowerShell 或 Admin tasks 窗格交給核准者。
  8. 把 Intune 稽核記錄路由到 Azure Monitor,並建立一份報告,依 actor.applicationId 與 actor.userPrincipalName 拆分 MAA 的核准、封鎖與放行事件。
  9. 完整試跑一遍:透過 412 往返建立一個指令碼,指派它,在測試裝置上強制同步,並確認稽核項目的呈現方式符合稽核人員的預期。
  10. 把程式碼固定在 beta URL,並留意 Intune What’s New 系列,注意搬遷到 v1.0 以及新增受保護類型的消息;列舉已經透露了 Microsoft 的方向。

需要多一雙手嗎?Big Hat Group 為美國與加拿大的組織提供 Microsoft Intune 諮詢服務,從兩週的健康檢查到完整移轉都能涵蓋。預約一次探索通話,聊聊你的環境。

參考來源