Remove-MgGroupMemberByRefの使い方:Entra IDグループから特定ユーザーだけ削除する手順と400エラー対処

Microsoft Graph PowerShell の Remove-MgGroupMemberByRef を使えば、Entra ID(Azure AD)グループから「特定ユーザーだけ」を外せます。ただし、UPN(user@domain)をそのまま渡せない、グループ種類によっては更新できない、400 BadRequest が出るなど“つまずきポイント”が多いのも事実です。この記事では、GUID の取得から削除手順、グループ削除との違い、エラー原因の切り分けと回避策までを運用目線でまとめます。

目次

Remove-MgGroupMemberByRef でできること・できないことを先に整理

Remove-MgGroupMemberByRef は、Microsoft Graph の「グループの members 参照($ref)を削除する」操作に相当します。重要なのは、実行時に必要なのがグループの GUID(GroupId)と対象ユーザーの GUID(DirectoryObjectId)である点です。表示名や UPN は“検索には使える”ものの、“削除コマンドにそのまま渡す”ことはできません。

やりたいこと使うコマンドポイント
特定ユーザーだけをグループから外すRemove-MgGroupMemberByRefGroupId と DirectoryObjectId(どちらも GUID)が必須
グループ自体を削除するRemove-MgGroup削除は“復元可能期間”がある(環境により条件が異なる)
動的グループのメンバーを外す(不可)ルールで決まるため、個別削除はできない
配布グループ/メール有効な一部グループのメンバーを外すGraph では不可のケースありExchange Online 側のコマンドで管理するのが一般的

ここから先は、「クラウド専用(Entra ID)グループから、狙ったユーザーだけを安全に外す」ための手順を、失敗しやすいポイント込みで解説します。

事前準備:Graph PowerShell の接続と最小スコープ

まずは Graph に接続します。実務では「操作に必要なスコープだけ」を付与し、不要に強い権限を避ける方が安全です。メンバー削除は少なくとも GroupMember.ReadWrite.All が必要になることが多く、グループ情報取得や運用の都合で Group.ReadWrite.All を併用するケースもあります。

# 例:メンバー削除に必要なスコープで接続
Connect-MgGraph -Scopes "GroupMember.ReadWrite.All","Group.ReadWrite.All"

テナント設定やロール(例:グループ管理者、ユーザー管理者、特権ロール管理者など)によっては、スコープを指定しても実行できないことがあります。スコープは“API への許可”、ロールは“実際に操作できる立場”と考えると切り分けしやすいです。

作業代表的な必要スコープ補足
グループ検索(displayName 等)Group.Read.All / Group.ReadWrite.All読み取りだけなら Read 系でも可
ユーザー検索(UPN 等)User.Read.All管理用途では必要になることが多い
グループのメンバー削除GroupMember.ReadWrite.All最重要。これがないと削除できない

なお、組織の運用ポリシーによっては「対話ログインが禁止」「アプリケーション権限で実行」などの条件があります。その場合は、Managed Identity / 証明書認証などの設計が必要ですが、この記事ではまず手元で検証しやすい対話ログインを前提に進めます。

最重要:UPN や表示名はそのまま渡せない(GUID を必ず取る)

Remove-MgGroupMemberByRef は、内部的には「/groups/{groupId}/members/{directoryObjectId}/$ref を DELETE」するイメージです。つまり、コマンドに渡すのは “人間が読める名前” ではなく “ディレクトリの一意キー(GUID)” になります。

人間が使う値Graph が求める値取得方法(代表例)
グループ表示名(displayName)GroupId(GUID)Get-MgGroup -Filter … → .Id
UPN(user@domain)DirectoryObjectId(GUID)Get-MgUser -UserId … → .Id
表示名(displayName)GUIDGet-MgUser -Filter …(同名に注意)

ここで躓きやすいのが「displayName でグループを引いたら複数ヒットした」「ユーザー表示名で検索したら同名がいた」などの“あいまい一致”です。運用では、重複しにくいキー(UPN、mail、外部 ID)で特定し、最終的に GUID で確定させる流れがおすすめです。

手順:GroupId と UserId(DirectoryObjectId)を取得して削除する

基本形は次の通りです。ポイントは「検索」と「削除」を分け、削除前に取得結果が“1件だけ”であることを確認することです。

# スコープを指定して接続(すでに接続済みなら不要)
Connect-MgGraph -Scopes "GroupMember.ReadWrite.All","Group.ReadWrite.All"

# 1) グループの GUID を取得
$group = Get-MgGroup -Filter "displayName eq 'Az-Grp-Team1'"
$groupId = $group.Id

# 2) ユーザーの GUID を取得(UPN から)
$user = Get-MgUser -UserId "[email protected]"
$userId = $user.Id

# 3) メンバー削除
Remove-MgGroupMemberByRef -GroupId $groupId -DirectoryObjectId $userId

このままでも動きますが、実務だと「グループが複数ヒット」「ユーザーが存在しない」「すでにメンバーではない」などが普通に起こります。次の“堅めの書き方”にすると事故が減ります。

運用向け:取得結果を検証してから削除する(安全重視)

Connect-MgGraph -Scopes "GroupMember.ReadWrite.All","Group.ReadWrite.All"

# グループ特定(displayName は重複し得るので要注意)

$groups = Get-MgGroup -Filter "displayName eq 'Az-Grp-Team1'"

if ($null -eq $groups) { throw "グループが見つかりませんでした。" }
if ($groups.Count -gt 1) {
throw "同名グループが複数あります。ObjectId(GUID)で特定してください。"
}

$groupId = $groups.Id

# ユーザー特定(UPN を使うのが安全)

$user = Get-MgUser -UserId "[[email protected]](mailto:[email protected])"
if ($null -eq $user) { throw "ユーザーが見つかりませんでした。" }

$userId = $user.Id

# すでにメンバーか確認(大量環境では All が重いので注意)

$members = Get-MgGroupMember -GroupId $groupId -All
$exists = $members.Id -contains $userId
if (-not $exists) {
Write-Host "対象ユーザーは現在メンバーではありません。削除はスキップします。"
return
}

# 削除実行

Remove-MgGroupMemberByRef -GroupId $groupId -DirectoryObjectId $userId
Write-Host "削除しました: $($user.UserPrincipalName) from $($groups.DisplayName)"

ポイントは次の3つです。

  • 重複し得る値(displayName)で即削除しない:必ず 1 件に確定させる
  • 存在チェック:ユーザーやメンバー状態を確認してから操作する
  • ログを残す:誰をどのグループから外したか記録できるようにする

「ユーザーを外す」のではなく「グループ自体を消したい」場合

グループそのものを削除したい場合は Remove-MgGroup を使います。メンバー削除とは別の操作なので、目的が「退職者を外す」なのか「プロジェクト終了でグループを廃止」なのかを最初に切り分けるのが重要です。

Connect-MgGraph -Scopes "Group.ReadWrite.All"

$groupId = (Get-MgGroup -Filter "displayName eq 'Az-Grp-Team1'").Id
Remove-MgGroup -GroupId $groupId

グループ削除は影響範囲が大きく、特に Microsoft 365 グループの場合は SharePoint サイト、Planner、Teams など周辺リソースにも波及します。削除前に最低限、次の情報を確認してから実行するのがおすすめです。

確認項目なぜ必要か確認のヒント
グループ種別(M365 / セキュリティ / 配布など)削除で失うものが変わるgroupTypes / mailEnabled / securityEnabled
所有者(Owners)復旧時・引継ぎの責任者になるGet-MgGroupOwner
メール有効かExchange 側管理の可能性があるmailEnabled が true
オンプレ同期かクラウドで更新できない場合があるonPremises* 系プロパティ

また、削除したグループは“復元可能な状態(削除済みアイテム)に入る”ことが一般的ですが、保持期間や復元可否はテナント設定や対象リソースによって変わることがあります。運用ポリシーに沿って、削除ではなく「利用停止(メンバーを空にする、動的ルールを外す、名前に廃止プレフィックスを付ける)」などの段階的な手順も検討してください。

400 BadRequest / Request_UnsupportedQuery が出るときの切り分け

GroupId と DirectoryObjectId を正しく入れたつもりでも、次のようなエラーに遭遇することがあります。

  • Unsupported referenced-object resource identifier for link property ‘members’.
  • Status: 400 (BadRequest)
  • ErrorCode: Request_UnsupportedQuery

この手のエラーは「ID が違う」という単純ミスだけでなく、“そのグループは Graph でメンバー更新できない”という設計上の制約でも起こります。ありがちな原因を、先に表でまとめます。

原因起きやすい症状確認方法代表的な対処
Graph で更新不可(Exchange 管理のグループ種別)400 / UnsupportedQuerymailEnabled=true の配布系・メール有効系Exchange Online PowerShell で管理
動的メンバーシップ(Dynamic Membership)個別追加/削除ができないgroupTypes に DynamicMembershipルール変更 or 静的グループ化
所有者(Owner)制約(最後の Owner など)削除に失敗、運用制約に当たるOwners を確認、最後の所有者になっていないか先に別 Owner を追加、Owner を外してからメンバー削除
オンプレ同期(AD Connect)でクラウドが書き換え不可更新系が通らない/エラーになるonPremises* 属性が埋まっているオンプレ AD でメンバー変更
SDK のバージョン差/不具合(パラメータが見えない等)-DirectoryObjectId が出ないGet-Command で Syntax を確認モジュール更新、別コマンド名、REST で代替

原因A:Graph で“更新不可”なグループ種別(特に Exchange 管理のもの)

配布グループやメール有効な一部グループは、Entra ID 上は「Group として見える」一方で、管理主体が Exchange 側になっていることがあります。この場合、Graph では読み取りはできても、メンバー更新が read-only 扱いになり、削除で 400 が出るパターンがあります。

見分けの近道は、まずグループのプロパティを“意図して”取りに行くことです。

# グループ種別の判断に使うプロパティを明示して取得
$g = Get-MgGroup -GroupId $groupId -Property "id,displayName,groupTypes,mailEnabled,securityEnabled,mail"

$g.DisplayName
$g.GroupTypes
$g.MailEnabled
$g.SecurityEnabled
$g.Mail

この結果を見て、次のように当たりを付けられます。

mailEnabledsecurityEnabledざっくり分類管理の注意点
falsetrueセキュリティグループ(クラウド専用)Graph で管理しやすい
truefalse配布グループの可能性Exchange Online 側での管理が必要になりやすい
truetrueメール有効なセキュリティグループの可能性Graph で更新不可の扱いになるケースに注意
true(任意)Microsoft 365 グループ(groupTypes に Unified)Owner/Team 連動など運用制約が出やすい

もし Exchange 管理が疑わしい場合は、Graph 側で無理に押し通すより、Exchange Online PowerShell(例:Remove-DistributionGroupMember) を検討するのが現実的です。API 的に“できる・できない”の領域は、操作を変えても解消しないことが多いためです。

原因B:動的メンバーシップ(Dynamic Membership)グループ

動的グループは、メンバーが「ルール」で決まります。個別に Remove-MgGroupMemberByRef を実行しても、設計上その操作が許可されないため失敗します。

動的かどうかは groupTypes と membershipRule で判断できます。

$g = Get-MgGroup -GroupId $groupId -Property "id,displayName,groupTypes,membershipRule,membershipRuleProcessingState"
$g.GroupTypes
$g.MembershipRule
$g.MembershipRuleProcessingState

動的グループだと分かったら、対処は次の方向になります。

  • ルールを変更して対象ユーザーが条件から外れるようにする
  • 一時的に静的グループを用意して運用を切り替える(移行期間を設ける)
  • 「動的グループを“参照”する」設計(アプリ側でフィルタ)に変える

個別削除を“頑張って通す”のではなく、ルール・設計を変えるのが正攻法です。

原因C:Owner(所有者)制約が絡む(Microsoft 365 グループ / Teams で特に注意)

Microsoft 365 グループ(Teams を含む)では、メンバーと Owner の概念が分かれます。対象ユーザーが Owner でもある場合、運用上の制約(例:最後の Owner を削除できない)が絡み、先に Owner を調整しないと削除が通らないことがあります。

まずは Owner を確認します。

# 所有者一覧を確認
Get-MgGroupOwner -GroupId $groupId -All | Select-Object Id

もし対象ユーザーが Owner に含まれるなら、次の順序で考えると安全です。

  • 別の Owner を追加(必要なら)
  • 対象ユーザーを Owner から外す
  • 対象ユーザーを Member から外す

現場では「退職者を外したい」ケースが多いですが、退職者がチームの Owner になっていることは珍しくありません。先に Owner を解消してからメンバー削除に進むと、ハマりにくくなります。

原因D:Graph PowerShell SDK のバージョン差・コマンド差

Graph PowerShell SDK は更新が活発で、バージョンによってはコマンドのパラメータ名が変わって見えたり、補助コマンドに置き換わっていたり、稀に不具合に遭遇することがあります。たとえば「Remove-MgGroupMemberByRef に -DirectoryObjectId が見当たらない」といったケースです。

まずは、いまの環境で“そのコマンドがどう見えているか”を確認します。

Get-Command Remove-MgGroupMemberByRef -Syntax
(Get-InstalledModule Microsoft.Graph).Version

対処の方向性は次の通りです。

  • モジュール更新:Update-Module Microsoft.Graph(運用規定がある場合は検証環境で)
  • コマンド名の揺れを疑う:同等操作の別コマンドが提供されていないか確認
  • REST で代替:Invoke-MgGraphRequest で API を直接叩く

特に運用現場では「急にパラメータが変わって自動化が止まった」を避けたいので、バージョン固定(例:特定バージョンを社内標準にし、更新は計画的に)を検討する価値があります。

原因E:オンプレ同期グループ(AD Connect)で“クラウド側がマスターではない”

「クラウド専用のつもりだったが、実はオンプレ AD から同期されていた」というのも、実務ではよくあります。オンプレ同期のオブジェクトは、クラウドで更新できない属性があり、メンバー管理もオンプレ側が正になる設計になりがちです。

判断材料として、グループに onPremises 系の情報が入っていないかを確認します。

$g = Get-MgGroup -GroupId $groupId -Property "id,displayName,onPremisesLastSyncDateTime,onPremisesSyncEnabled,onPremisesSecurityIdentifier"
$g.OnPremisesSyncEnabled
$g.OnPremisesLastSyncDateTime
$g.OnPremisesSecurityIdentifier

同期が疑われる場合は、Graph での削除に固執せず、オンプレ AD のメンバーシップを変更して同期させるのが最短ルートです。クラウド側で無理に変更しようとしても、設計上の制約で弾かれるだけのことが多いです。

それでも削除できないときの最終手段:REST(Invoke-MgGraphRequest)で切り分け

PowerShell コマンドのラッパーが原因なのか、API 自体が制約なのかを切り分けたいときは、Graph REST を直接叩くと判断が早くなります。PowerShell SDK の挙動差を回避できることもあります。

# /groups/{groupId}/members/{userId}/$ref を DELETE
$uri = "/groups/$groupId/members/$userId/`$ref"
Invoke-MgGraphRequest -Method DELETE -Uri $uri

ここで REST でも失敗するなら、ほぼ間違いなく「グループ種別・動的・同期・権限」のどれかが原因です。逆に REST では成功するのにコマンドで失敗するなら、SDK 側の差異・不具合の可能性が上がります。

実務で差が出る:削除前後の確認・監査ログ・ロールバックを意識する

「削除できたかどうか」は、コマンドがエラーを返さないだけでは不十分です。反映遅延やキャッシュの影響もあり得るため、削除後にもう一度メンバー一覧を確認する癖を付けると事故が減ります。

削除後の確認(簡易)

$members = Get-MgGroupMember -GroupId $groupId -All
if ($members.Id -contains $userId) {
  Write-Host "まだメンバーに残っています(反映遅延の可能性もあります)"
} else {
  Write-Host "メンバーから外れていることを確認しました"
}

CSV で複数ユーザーを外す(運用の定番)

退職者処理や異動対応では、複数ユーザーを同じグループから外すことが多いです。CSV を前提にすると、手作業ミスが減り、証跡も残しやすくなります。

Connect-MgGraph -Scopes "GroupMember.ReadWrite.All","Group.ReadWrite.All","User.Read.All"

$groupId = (Get-MgGroup -Filter "displayName eq 'Az-Grp-Team1'").Id
$csv = Import-Csv ".\remove_users.csv"   # 例:UPN 列を持つ CSV(UPN: user@domain)

foreach ($row in $csv) {
  try {
    $user = Get-MgUser -UserId $row.UPN
    if ($null -eq $user) {
      Write-Warning "ユーザーが見つかりません: $($row.UPN)"
      continue
    }

    Remove-MgGroupMemberByRef -GroupId $groupId -DirectoryObjectId $user.Id
    Write-Host "削除: $($row.UPN)"
  }
  catch {
    Write-Warning "失敗: $($row.UPN) / $($_.Exception.Message)"
  }
}

CSV 運用のコツは次の通りです。

  • CSV は UPN のみでなく、社員番号などの社内キーも列に持たせると、追跡が楽
  • 実行ログ(成功/失敗/理由)をファイルに出すと監査対応が楽
  • 削除前に「対象が本当にそのグループのメンバーか」を確認して無駄な API 呼び出しを減らす

トラブルシューティング:チェック項目を上から潰すだけで原因に近づく

最後に、現場でそのまま使えるチェックリストを載せます。400 系エラーに限らず「思った通りに削除できない」ときは、この順で確認すると遠回りしにくいです。

  • GUID は正しいか:GroupId と DirectoryObjectId を取り違えていないか(文字列の貼り間違いが多い)
  • 対象ユーザーは存在するか:Get-MgUser -UserId で取得できるか
  • 対象ユーザーはメンバーか:Get-MgGroupMember で実在を確認
  • 必要スコープで接続しているか:GroupMember.ReadWrite.All を含むか
  • グループ種別は更新可能か:mailEnabled/securityEnabled/groupTypes を確認
  • 動的グループではないか:DynamicMembership を含むか
  • オンプレ同期ではないか:onPremisesSyncEnabled を確認
  • Owner 制約に当たっていないか:対象が Owner で、最後の Owner になっていないか
  • SDK の問題ではないか:Get-Command で Syntax を確認、必要なら REST で再現性を確認

Remove-MgGroupMemberByRef は、仕組みを理解すると非常に強力です。逆に、グループ種別や同期/動的といった「ディレクトリ設計の前提」を見落とすと、どれだけ ID を見直しても解決しません。まずは GroupId と DirectoryObjectId を確実に取得し、次に そのグループが Graph で更新できる種類かを確認する——この2段階を押さえるだけで、成功率は大きく上がります。

この記事を書いた人

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

コメント

コメントする

目次