Microsoft Entra ID(旧 Azure AD)の PIM ロールを PowerShell から有効化しようとしたところ、MfaRule が原因で RoleAssignmentRequestPolicyValidationFailed やサインイン エラー 500186 になり、手詰まりになっていないでしょうか。ポータルからは問題なく有効化できるのに、スクリプトだけが失敗する場合、多くは「条件付きアクセスや PIM ポリシーの MFA 要求」と「PowerShell で取得したトークンの中身」が噛み合っていないことが原因です。この記事では、原因の仕組みを分解しながら、PowerShell(Microsoft Graph PowerShell)で PIM ロールを安定して有効化する具体的な対処方法を詳しく解説します。
PowerShell から PIM ロールを有効化しようとすると何が起きているのか
まずは、よく見られる症状を整理します。次のような状況で困っているケースが多いはずです。
| 状況 | 具体的な症状・メッセージ |
|---|---|
| PowerShell から PIM ロール有効化 | New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest を実行すると失敗 エラー: RoleAssignmentRequestPolicyValidationFailed メッセージ: The following policy rules failed: ["MfaRule"] |
| サインイン ログ | サインイン エラー コード 500186 内容: ポリシー条件により許可されない / 多要素認証が必要 |
| ユーザーの体感 | PowerShell 実行時、MFA の追加確認が求められない Microsoft Authenticator に通知も来ない 同じユーザーで、Entra 管理センター(ポータル)から PIM ロールを手動有効化すると成功する |
つまり、ポータルからは通るのに PowerShell からだと MfaRule でブロックされるという状態です。
MfaRule と amr=mfa クレームの関係
なぜこのような差が出るのかを理解するには、トークンのクレーム、とくに amr クレームについて知っておく必要があります。
| 用語 | 意味 |
|---|---|
| 条件付きアクセス(CA) | ユーザー/アプリ/操作の条件に応じて「MFA 必須」などを強制するポリシー。 |
| PIM ポリシー | PIM ロールの有効化時に「MFA が必須」「理由の入力必須」などを定義するロール専用ポリシー。 |
MfaRule | 「この操作は MFA 済みトークンでなければダメ」というポリシー ルール。 |
amr クレーム | Authentication Methods References。認証方法の実績が入るクレーム。MFA を実施すると通常 amr に mfa が含まれる。 |
amr=mfa | トークン内に「このサインインは MFA を伴った」という証跡が含まれている状態。 |
条件付きアクセスや PIM の MfaRule は、「現在使っているトークンに amr=mfa があるかどうか」をチェックしています。
ポータルから PIM を操作するときは、ブラウザー上でのサインインに対して自然に MFA が走るため、得られるトークンに amr=mfa が入り、問題なく MfaRule を満たせます。
ところが PowerShell から Graph に接続する場合、サインインの流れが少し違います。
根本原因:PowerShell のトークンに amr=mfa が含まれていない
今回のようなエラーの本質的な原因は、次の 2 点に集約できます。
- 条件付きアクセスや PIM ポリシーで「MFA が必須」になっている
- しかし、PowerShell で取得したアクセストークンに
amr=mfaが含まれていない
ここでポイントになるのが「トークン キャッシュ」です。
Connect-MgGraphを一度実行すると、そのプロセスの中でアクセストークンがキャッシュされる- 同じプロセスで再度
Connect-MgGraphを実行すると、MFA なしで既存トークンが silently 再利用されることがある - その結果、MFA をしていない古いトークンで PIM API を呼びにいき、
MfaRuleに引っ掛かる
つまり、ユーザーの感覚としては「毎回サインイン画面が出ていたから、MFA も通っているはず」と思っていても、実際にはトークン使い回しで amr=mfa が付いていない、というギャップが生じているわけです。
ポータル操作と PowerShell 操作の違い
ブラウザーからポータル(Entra 管理センター)にアクセスした場合と、PowerShell(Graph PowerShell)でサインインした場合の違いをざっくり比較すると、次のようになります。
| 項目 | ポータル(ブラウザー) | PowerShell(Graph PowerShell) |
|---|---|---|
| サインイン UI | ブラウザー内。MFA プロンプトも同じブラウザー/アプリで誘導。 | デバイスの既定ブラウザーでサインイン画面を開くが、トークンは PowerShell プロセス内でキャッシュ。 |
| MFA 実施の強制 | 条件付きアクセスが直接ブラウザー セッションに適用される。 | トークン キャッシュが生きていると、再認証なしでトークン再利用されることがある。 |
amr=mfa の付きやすさ | MFA プロンプト後のトークンにはほぼ確実に含まれる。 | MFA していない古いトークンを掴んでいると amr=mfa が付かない。 |
| PIM ロール有効化 | 問題なく MfaRule を満たして有効化できる。 | MfaRule により RoleAssignmentRequestPolicyValidationFailed になる。 |
解決策:Connect-MgGraph で MFA を強制するクレームを付与する
最もシンプルで汎用性が高い解決策は、サインイン時に「MFA を強制するクレーム」を要求してからコマンドを実行することです。具体的には、Connect-MgGraph に -ExtraQueryParameters を指定し、amr=mfa を要求します。
基本パターンのスクリプト例
# 既存セッションの切断(念のため)
Disconnect-MgGraph 2>$null
# MFA 実施を強制するクレームを付けてサインイン
Connect-MgGraph `
-Scopes "RoleManagement.ReadWrite.Directory","Directory.Read.All" `
-ContextScope Process `
-ExtraQueryParameters @{claims='{"access_token":{"amr":{"values":["mfa"]}}}'}
# 例:PIM(ディレクトリ ロール)の自己有効化リクエスト
New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest `
-Action "SelfActivate" `
-PrincipalId "<あなたのユーザー オブジェクトID>" `
-RoleDefinitionId "<対象ロールの定義ID>" `
-DirectoryScopeId "/" `
-Justification "自動化ジョブの実行のため" `
-ScheduleInfo @{
startDateTime = (Get-Date).ToUniversalTime().ToString("o")
expiration = @{ type = "AfterDuration"; duration = "PT1H" } # 例:1時間
}
ここで重要なポイントは -ExtraQueryParameters に指定している claims 引数です。
@{claims='{"access_token":{"amr":{"values":["mfa"]}}}'}
このクレームにより、サインイン時に必ず MFA の追加認証が発生し、得られるアクセストークンに amr=mfa が含まれるようになります。結果として、PIM 側の MfaRule の検証を通過できるようになります。
Connect-MgGraph 実行時の挙動
修正後の Connect-MgGraph を実行すると、次のような挙動が確認できます。
- ブラウザーが開き、通常のサインイン画面が表示される
- サインイン後、MFA の追加認証(Authenticator 通知やコード入力など)が必ず発生する
- 認証完了後、PowerShell 側で
AccountやScopesが設定された状態で接続が完了する
これにより、PIM API を呼び出す際には、MFA 実施済みのトークンが必ず使われることになります。
-ContextScope Process を付ける意味
上記の例では、あえて -ContextScope Process を付けています。これには次のような狙いがあります。
| 設定 | 意味 / 効果 |
|---|---|
-ContextScope Process あり | トークンが「プロセス単位」で管理される 別の PowerShell セッション間でトークンが共有されにくくなる 古いトークンがどこからか再利用されるリスクを抑えられる |
-ContextScope 指定なし | 環境によってはより広いスコープでキャッシュされることがある 意図せず過去のセッションのトークンを再利用してしまうことがある |
特に PIM のように「MFA 実施済みトークン」であることが重要な操作では、プロセスを分けて都度クリーンな状態で接続するのがおすすめです。
「PIM 用 PowerShell」は、他と混ぜずに専用ウィンドウで実行する運用にしておくとトラブルを減らせます。
代替手段:MSAL を直接使ってクレーム付きトークンを取得する
PowerShell 7 のみを使っていたり、独自のサインイン フローを組みたい場合は、MSAL(Microsoft Authentication Library)を直接使ってトークンを取得する方法もあります。
MSAL.PS を使う例
まず、MSAL.PS モジュールをまだ入れていない場合はインストールします。
Install-Module MSAL.PS -Scope CurrentUser
次に、クレーム付きでトークンを取得し、そのトークンを使って Graph に接続します。
$tenantId = "<テナントID>"
$clientId = "<パブリッククライアントID>" # 例:Azure AD PowerShell 用などの公開クライアント ID
# MFA を強制するクレーム
$claims = '{"access_token":{"amr":{"values":["mfa"]}}}'
# インタラクティブにトークンを取得
$token = Get-MsalToken `
-TenantId $tenantId `
-ClientId $clientId `
-Interactive `
-Scopes "https://graph.microsoft.com/.default" `
-Claims $claims
# 取得したアクセストークンで Graph に接続
Connect-MgGraph -AccessToken $token.AccessToken
# あとは同様に PIM API を実行
New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest ...
この方法でも、MSAL にクレームを渡すことで MFA を強制し、amr=mfa 付きのトークンを得ることができます。Connect-MgGraph の動きに依存したくない場合や、複数の API(Graph 以外)を同一トークンで呼びたい場合に有効です。
トークン再利用(キャッシュ)による問題の抑止策
今回のようなトラブルを再発させないためには、「トークンキャッシュが何をしているか」を少し意識しておくと安心です。
推奨される運用パターン
| シナリオ | 推奨パターン |
|---|---|
| PIM ロールを手動で有効化するスクリプト | 専用の PowerShell ウィンドウでのみ実行 開始時に Disconnect-MgGraph 2>$null を実行 Connect-MgGraph -ContextScope Process -ExtraQueryParameters @{claims=...} を必ず通す |
| 管理者がインタラクティブに操作するバッチ | スクリプトの冒頭で Connect-MgGraph ... を呼び出す スクリプトの最後に Disconnect-MgGraph を実行 |
| 自動化ジョブ(非対話) | 基本的に「人の MFA」を前提にした自動実行は避ける サービスプリンシパル+証明書認証などを検討しつつ、条件付きアクセスの設計を見直す |
特に注意したいのが、Disconnect-MgGraph を実行しても「同一プロセス」のキャッシュが残ることがあるという点です。そのため、「セッションを切り離したつもりでも、実は古いトークンを使っていた」という落とし穴にハマりがちです。
最も安全なのは、「PIM を触るときは新しく PowerShell を開き直す」というシンプルな運用ルールを徹底することです。
切り分けチェックリスト
トラブルシューティング時に確認したいポイントをチェックリスト形式でまとめます。
| チェック項目 | 確認内容 |
|---|---|
| サインイン ログのエラーコード | Entra ID のサインイン ログで、エラーコード 500186 が出ているか 詳細に「多要素認証が必要」「ポリシー条件によりアクセス不可」などと表示されているか |
| 条件付きアクセスの設定 | 対象ユーザー/アプリ/操作に対し、MFA 必須のポリシーが適用されていないか 認証強度(多要素認証/フィッシング耐性 MFA 等)のポリシーが有効になっていないか |
| PIM ロール設定 | 対象ロールの PIM ポリシーで「アクティベーション時に MFA 必須」となっているか ポータル操作では問題なく有効化できるか(比較のため) |
| ユーザーの認証方法設定 | Microsoft Authenticator または許可された MFA 方法が登録されているか 認証方法ポリシーでブロックされていないか |
| PowerShell セッション状態 | 新しい PowerShell ウィンドウで試しているか Connect-MgGraph 前に古いセッションを切断しているか |
| Graph PowerShell モジュール | Microsoft.Graph モジュールが最新に近いバージョンになっているか 古い AzureAD / AzureADPreview モジュールを前提としたスクリプトが残っていないか |
上記を一通り確認し、特に「条件付きアクセス」「PIM ポリシー」「トークン取得方法」の 3 点が噛み合っているかをチェックすることで、原因の切り分けがしやすくなります。
よくある落とし穴とその回避策
Disconnect-MgGraph だけでは足りないことがある
前述の通り、Disconnect-MgGraph はセッションの切断には有効ですが、同一プロセス内のトークンキャッシュを完全に消さないことがあります。
そのため、次のような運用が安全です。
- PIM 用スクリプトは「新しい PowerShell ウィンドウ」で起動する
- スクリプト冒頭で
Disconnect-MgGraph 2>$nullを呼ぶ Connect-MgGraph -ContextScope Process -ExtraQueryParameters @{claims=...}を必ず通す
旧 AzureAD モジュールを使い続けている
すでに非推奨となった AzureAD / AzureADPreview モジュールは、今後の更新やサポートが期待できません。
PIM を含む管理系操作は、Microsoft Graph PowerShell と MSAL ベースの認証を前提に設計し直すことをおすすめします。
- 新規スクリプトは必ず
Microsoft.Graph.*モジュールを使用 - 既存スクリプトも段階的に Graph API ベースへ移行
- MFA 必須の操作は、今回紹介したようなクレーム付きサインインに集約
認証強度ポリシーと amr=mfa のギャップ
条件付きアクセスの「認証強度(Authentication Strength)」を使っている環境では、amr=mfa だけでは不十分なことがあります。
例えば、「フィッシング耐性 MFA」が必須になっている場合、単なるスマホ通知型 MFA では条件を満たせません。
このようなケースでは、
- 要求されている認証強度の内容を確認する
- ユーザーがその強度を満たせる認証方法を登録しているか確認する
- テスト目的で一時的にポリシーを緩め、問題の切り分けを行う
といったステップを踏むことで、「MFA の種類が足りない」のか「トークンに証跡が載っていないだけなのか」を明確にできます。
実運用を意識した PIM ロール有効化スクリプト例
最後に、実運用で使いやすいように少し整理したサンプル スクリプトを紹介します。
特定の PIM ロールを自己有効化し、一定時間だけアクティブにするシナリオを想定しています。
param(
[Parameter(Mandatory)]
[string]$RoleDefinitionId, # 対象ロールの定義 ID
[Parameter(Mandatory)]
[string]$Justification, # 理由(監査ログに残る)
[string]$Duration = "PT1H" # 有効化時間 (ISO 8601 形式, 例: PT1H)
)
# ===== 共通設定 =====
$scopes = @(
"RoleManagement.ReadWrite.Directory",
"Directory.Read.All"
)
# ===== サインイン(MFA を強制) =====
Write-Host "Microsoft Graph にサインインしています(MFA 必須)..."
Disconnect-MgGraph 2>$null
$claims = '{"access_token":{"amr":{"values":["mfa"]}}}'
Connect-MgGraph `
-Scopes $scopes `
-ContextScope Process `
-ExtraQueryParameters @{ claims = $claims }
# ===== ユーザー情報の取得 =====
$ctx = Get-MgContext
$me = Get-MgUser -UserId $ctx.Account
Write-Host "サインイン ユーザー:" $me.DisplayName "("$me.Id")"
# ===== PIM ロールの自己有効化要求 =====
$start = (Get-Date).ToUniversalTime().ToString("o")
Write-Host "PIM ロールを有効化しています..."
$request = New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest `
-Action "SelfActivate" `
-PrincipalId $me.Id `
-RoleDefinitionId $RoleDefinitionId `
-DirectoryScopeId "/" `
-Justification $Justification `
-ScheduleInfo @{
startDateTime = $start
expiration = @{
type = "AfterDuration"
duration = $Duration
}
}
Write-Host "要求 ID:" $request.Id
Write-Host "状態 :" $request.Status
if ($request.Status -ne "Provisioned" -and $request.Status -ne "PendingApproval") {
Write-Warning "ロール有効化要求の状態が想定外です。サインイン ログおよび PIM 画面で詳細を確認してください。"
}
このテンプレートをベースに、
- ロール定義 ID を環境ごとに管理する
- ジョブ名やチケット番号を
$Justificationに含める - 有効化時間(
$Duration)をジョブ内容に応じて変更する
など、自社の運用に合わせたカスタマイズを行うことで、「毎回ポータルを開かなくても、安全に PIM ロールを有効化できる仕組み」を作ることができます。
まとめ
- PowerShell(Microsoft Graph PowerShell)から PIM ロールの有効化を行う際に、
MfaRuleでRoleAssignmentRequestPolicyValidationFailedやサインイン エラー 500186 が発生する主な原因は、トークンにamr=mfaが含まれていないことです。 - 条件付きアクセスや PIM ポリシーで MFA が必須のとき、サインイン時に MFA を強制するクレームを要求することで問題を回避できます。
Connect-MgGraph -ExtraQueryParameters @{claims='{"access_token":{"amr":{"values":["mfa"]}}}'}を利用することで、MFA 実施済みトークンを確実に取得できます。-ContextScope Processを活用し、新しい PowerShell ウィンドウで実行することで、古いトークンの再利用によるトラブルを防止できます。- 必要に応じて MSAL を直接利用する方法や、認証強度ポリシーとの整合も確認し、ポータルと同等レベルのセキュリティを保ちながら自動化・スクリプト化を進めましょう。
「ポータルでは動くのにスクリプトだけ失敗する」という現象は、仕組みを理解してしまえば再現性高くコントロールできます。
今回紹介した方法で、PowerShell からの PIM ロール有効化を安全かつ安定した形で運用してみてください。

コメント