Entra IDのユーザー/ゲストに7日後の有効期限を設定して自動でアカウント無効化する方法【Microsoft Graph PowerShell】

一時ユーザーやベンダーのゲストをEntra IDに登録したあと、「7日後に自動でサインイン不可にしたい…でも手動運用は避けたい」というニーズはとても多いです。本記事では、Microsoft Graph PowerShellを使ってemployeeLeaveDateTimeに有効期限を設定し、期日を過ぎたユーザー/ゲストを自動でaccountEnabled = falseへ切り替える、実務向けの実装パターンを丁寧に解説します。

目次

Entra IDユーザー/ゲストに「7日後の有効期限」を付けたい典型シナリオ

まず、今回の要件を整理します。

  • Entra ID(旧Azure AD)のユーザーまたはゲストに「有効期限日」を持たせたい
  • 期限日を過ぎたら、そのアカウントはサインインできない状態(= 無効化)にしたい
  • できれば PowerShell で自動化し、毎日バッチ的に処理したい
  • 対象は社内ユーザーだけでなく、B2Bゲストも含めたい

よくある使い方としては次のようなものがあります。

  • 検証用に作る一時アカウント(PoCユーザー)
  • 短期間だけ社内環境へアクセスするベンダーやパートナー
  • イベント参加者やセミナー講師向けの一時ゲスト

こうしたアカウントを「作りっぱなし」にしないために、Entra IDに有効期限を持たせる仕組みを作っておくと、セキュリティ・運用の両面でかなり安心できます。

実現方針の全体像

Microsoft Entra ID(旧Azure AD)には「アカウントの有効期限」を自動で判定して無効化してくれる標準機能はありません。しかし、ユーザーオブジェクトの属性をうまく組み合わせることで、ほぼ同じことを実現できます。

やりたいことEntra ID での実現手段
有効期限日を保存したいemployeeLeaveDateTime 属性に期限を保存する
期限を過ぎたらサインイン不可スクリプトで期限超過ユーザーを検知し、accountEnabled = false に更新
ゲスト(B2B)も同様に扱いたいゲストもユーザーオブジェクト(userType = Guest)なので同じロジックを適用

つまり構成は次のようになります。

  1. 期限日を employeeLeaveDateTime に保存(例:今日から7日後のUTC)
  2. 毎日実行されるPowerShellジョブで
    • employeeLeaveDateTime <= 現在時刻
    • かつ accountEnabled = true
    のユーザーを探す
  3. 該当ユーザーの accountEnabled を false に更新する

この仕組みを Windows タスク スケジューラや Azure Automation に乗せてしまえば、「有効期限付きユーザー/ゲスト」の運用をかなり自動化できます。

employeeLeaveDateTime 属性とは?

employeeLeaveDateTime は、ユーザーが組織を離れる日時を表すための属性です。Microsoft Entra Identity Governance のライフサイクルワークフロー(退職者/契約終了者向けの自動処理)でトリガーに使われることを想定して用意されています。

この属性のポイントは次の通りです。

項目内容
用途ユーザーの「離職日」「契約終了日」などの日時を保持する
型DateTimeOffset(REST APIでは YYYY-MM-DDThh:mm:ssZ 形式)
設定方法Graph API / Microsoft Graph PowerShell / Entra Connect などから設定
ポータルUI現時点ではEntra ポータルのユーザー画面からは直接編集できない
注意点この属性を設定するだけではアカウントは自動で無効化されない

つまり「有効期限日を保存する箱」としては非常に便利ですが、停止処理そのものは自前スクリプトで補う必要があります。

Microsoft Graph PowerShell SDKの準備

今回の実装では、AzureAD / MSOnline モジュールではなく、Microsoft Graph PowerShell SDK を利用します。Azure AD関連の旧モジュールはすでに非推奨となっているため、現在は Graph モジュールへの移行が推奨されています。

モジュールのインストール

# 管理者権限の PowerShell で実行
Install-Module Microsoft.Graph -Scope CurrentUser

権限付きで接続する

employeeLeaveDateTime の読み書きには、通常のユーザー属性とは別に「ライフサイクル情報用」の権限が必要です。2025年時点の公式ドキュメントでは、以下のような権限構成が案内されています。

  • employeeLeaveDateTime を更新:
    • User.Read.All
    • User-LifeCycleInfo.ReadWrite.All
  • accountEnabled を更新:
    • User.Read.All
    • User.EnableDisableAccount.All

PoCや小規模環境であれば、管理者アカウントで次のように接続しておくと一通りの操作が行えます(実運用では必要最小限の権限に絞ることを推奨します)。

Connect-MgGraph -Scopes `
  "User.Read.All", `
  "User.ReadWrite.All", `
  "User-LifeCycleInfo.ReadWrite.All", `
  "User.EnableDisableAccount.All"

# v1.0 プロファイルを使用
Select-MgProfile -Name "v1.0"

無人実行(サービスプリンシパル+証明書)にする場合は、アプリケーション権限として同等のパーミッションを付与し、-TenantId と -ClientId、-CertificateThumbprint を指定して接続します。

単一のユーザー/ゲストに7日後の有効期限を設定する

ここから具体的な PowerShell の例を見ていきます。まずは1件のユーザー(またはゲスト)に「7日後の有効期限」を設定するコードです。

基本のPowerShellコード(1件)

# 事前に Connect-MgGraph で接続しておく

# 対象ユーザーのUPN またはオブジェクトID
$UserId = "[email protected]"

# 7日後のUTC日時を計算
$ExpirationUtc = [DateTimeOffset]::UtcNow.AddDays(7)

# employeeLeaveDateTime に有効期限を設定
Update-MgUser -UserId $UserId -EmployeeLeaveDateTime $ExpirationUtc

よくあるミスとチェックポイントを挙げておきます。

  • AddDays() の引数を忘れてエラー
    • (Get-Date).AddDays() のように引数なしは不可
    • 必ず AddDays(7) のように数値を渡す
  • Update-MgUser の権限不足
    • User-LifeCycleInfo.ReadWrite.All が付与されているか確認
    • アプリの場合はアプリケーション権限に付与し、管理者承認済みであること
  • -AccountEnabled $false を同時に指定してしまう
    • これを指定すると即座にアカウントが停止する
    • 「期限日になったら止めたい」場合は、このタイミングでは絶対に指定しない

今日を有効期限にして即日失効させたい場合

「明日以降は入らせたくないので今日いっぱいで失効にしたい」という場合は、単純に AddDays(0) か UtcNow を使います。

# 今日の時点で失効させたい例
$UserId = "[email protected]"
$ExpirationUtc = [DateTimeOffset]::UtcNow  # または .AddDays(0)

Update-MgUser -UserId $UserId -EmployeeLeaveDateTime $ExpirationUtc

この場合、後述の自動無効化ジョブが「期限を過ぎたユーザー」と判定して、次回実行時に accountEnabled を false に変更してくれます。

設定結果を確認する

employeeLeaveDateTime は「指定したプロパティだけ返す」挙動のため、Get-MgUser で明示的にプロパティ名を指定するのが確実です。

Get-MgUser -UserId $UserId `
  -Property Id,DisplayName,AccountEnabled,EmployeeLeaveDateTime |
  Select-Object DisplayName,AccountEnabled,EmployeeLeaveDateTime

ここで EmployeeLeaveDateTime に意図したUTC日時が入っていればOKです。

期日超過ユーザーを自動で無効化する仕組み

次に「期日を過ぎたユーザーを無効化する」PowerShellバッチを作成します。このバッチを1日1回などで実行することで、自動停止が実現できます。

判定ロジック

やりたいことを条件に落とすと、次のようになります。

  • EmployeeLeaveDateTime が設定されている
  • EmployeeLeaveDateTime <= 現在時刻 (UTC)
  • AccountEnabled = true(まだ有効化されている)

この条件を満たすユーザーだけを探し出し、Update-MgUser で AccountEnabled = false に更新します。

シンプルなPowerShellバッチ例

# 事前にアプリ or 管理者アカウントで Connect-MgGraph しておく
# (例:アプリケーション権限での接続)
# Connect-MgGraph -TenantId "&lt;tenantId&gt;" -ClientId "&lt;appId&gt;" -CertificateThumbprint "&lt;thumbprint&gt;"
# Select-MgProfile -Name "v1.0"

$now = [DateTimeOffset]::UtcNow

# ログ出力用
$log = @()

# すべてのユーザーを取得(必要なプロパティだけ)
$users = Get-MgUser -All `
  -Property Id,DisplayName,UserPrincipalName,AccountEnabled,EmployeeLeaveDateTime,UserType

$targets = $users | Where-Object {
    $_.EmployeeLeaveDateTime -and              # 期限日が設定されている
    $_.EmployeeLeaveDateTime -le $now -and     # 期限を過ぎている
    $_.AccountEnabled -eq $true                # まだ有効
}

foreach ($u in $targets) {
    Write-Host "Disable: $($u.DisplayName) ($($u.UserPrincipalName))"

    # アカウントを無効化
    Update-MgUser -UserId $u.Id -AccountEnabled:$false

    # ログ用に記録
    $log += [PSCustomObject]@{
        Timestamp   = $now
        UserId      = $u.Id
        UPN         = $u.UserPrincipalName
        DisplayName = $u.DisplayName
        UserType    = $u.UserType
        LeaveDate   = $u.EmployeeLeaveDateTime
    }
}

# ログをCSVに出力(パスは環境に合わせて変更)
if ($log.Count -gt 0) {
    $logPath = "C:\Logs\Entra-UserDisable-$(Get-Date -Format 'yyyyMMdd-HHmmss').csv"
    $log | Export-Csv -Path $logPath -NoTypeInformation -Encoding UTF8
}

ポイントを整理します。

  • -Property で必要な属性を列挙
    • EmployeeLeaveDateTime や AccountEnabled は $select(PowerShellの -Property)で明示しないと返ってこないケースがあるため、必ず指定します。
  • ログを必ず残す
    • いつ・誰が・どのユーザーを無効化したかを追えるように、CSVなどに記録しておくと運用上安心です。
  • 対象ユーザーの絞り込み
    • 必要に応じて Where-Object { $_.UserType -eq "Guest" } などを加えれば、「ゲストだけ」「メンバーだけ」にもできます。

実行環境の候補と比較

実行環境メリットデメリット
Windows タスク スケジューラオンプレでもすぐ使える/既存管理サーバーで完結サーバー障害時に止まりやすい/証明書・秘密情報の管理が必要
Azure Automationクラウド側で完結/Run As アカウントやマネージドIDで安全に実行しやすい若干の初期セットアップが必要/課金モデルの理解が必要
Azure Functions / Logic Appsイベントドリブンなど柔軟な拡張が可能スクリプトだけでなくコード/ワークフロー設計が必要になりがち

まずは Windows タスク スケジューラやAzure Automationで「毎日〇時に実行」のバッチとして組む形が、シンプルでおすすめです。

ゲスト(B2B)ユーザーへも同じ仕組みを適用する

Entra ID の B2Bゲストも、内部的にはユーザーオブジェクトであり、userType = Guest という違いがあるだけです。そのため、ここまで紹介した employeeLeaveDateTime と accountEnabled の組み合わせは、そのままゲストにも適用できます。

ゲストだけに7日後の期限を設定する例

たとえば、「特定グループのゲスト全員に7日後の有効期限を設定したい」という場合は、以下のようなスクリプトで一括設定できます。

$groupId = "&lt;対象グループのObjectId&gt;"
$expirationUtc = [DateTimeOffset]::UtcNow.AddDays(7)

# グループメンバーを取得
$members = Get-MgGroupMember -GroupId $groupId -All

foreach ($m in $members) {
    # ユーザーだけ(ゲスト含む)に絞る
    if ($m.'@odata.type' -eq "#microsoft.graph.user") {
        $user = Get-MgUser -UserId $m.Id -Property Id,UserType,DisplayName

        if ($user.UserType -eq "Guest") {
            Write-Host "Set expiration for guest: $($user.DisplayName)"

            Update-MgUser -UserId $user.Id -EmployeeLeaveDateTime $expirationUtc
        }
    }
}

あとは前述の「毎日実行ジョブ」に任せれば、7日後に自動で AccountEnabled = false へ切り替わります。

招待直後に有効期限を設定する運用

ゲストの招待を New-MgInvitation などで自動化している場合は、招待実行直後に該当ゲストユーザーのIDを取得して employeeLeaveDateTime を更新するという流れにすると綺麗にまとまります。

  1. New-MgInvitation でゲストを招待
  2. レスポンスの InvitedUser からゲストのユーザーIDを取得
  3. Update-MgUser -EmployeeLeaveDateTime で期限を設定

こうしておけば「この招待は7日後に自動停止する」という状態を、完全にコード上で一貫して扱えます。

Entra ID Governanceと組み合わせる場合

Entra ID Governance(有償ライセンス)には、アクセス レビューやエンタイトルメント管理、ライフサイクルワークフローなど、豊富な自動化機能が含まれています。これらの機能でも、employeeLeaveDateTime をトリガーにして各種処理(グループからの削除・ライセンス解除など)を実行できます。

ただし、ここで重要なのは、Entra ID Governance が扱うのは主に「アクセス権の自動剥奪」であり、ユーザーオブジェクト自体の accountEnabled を必ずしも無効化してくれるわけではない、という点です。

  • Governance:グループメンバーシップ、アプリケーション割り当て、ライセンスなどを自動解除
  • 今回のスクリプト:ユーザーオブジェクトそのものを「無効アカウント」にする

「ゲストが将来また別の用途で招待される可能性があるので、完全に削除はしたくないが、現状のアクセスは止めたい」といったケースでは、

  • Entra ID Governanceで権限・割り当てを削除
  • 今回のスクリプトで accountEnabled を無効化

という二段構えにすることで、より堅牢な運用ができます。

実装上の注意点とよくある落とし穴

UTCとローカル時刻の混在に注意

Graph API は基本的にUTCを前提としているため、必ず [DateTimeOffset]::UtcNow を基準に計算することをおすすめします。ローカル時刻(Get-Date)をそのまま渡しても自動でUTC変換は行われますが、タイムゾーンの設定や夏時間の扱いで混乱しやすくなります。

  • 有効期限の設定:
    • [DateTimeOffset]::UtcNow.AddDays(7) のようにUTCを基準にする
  • ログ出力:
    • 人間の目で見やすいように、CSVにはローカル時刻とUTCの両方を記録しておくのも有効

テスト環境でのドライラン(WhatIf相当)

最初から本番ユーザー全体に対して実行するのは非常に危険です。まずは「ドライラン」として「無効化候補をログに出すだけ」のモードで動かすと安全です。

# ドライラン例:無効化はせず、対象ユーザーだけ表示

$now = [DateTimeOffset]::UtcNow

$users = Get-MgUser -All `
  -Property Id,DisplayName,UserPrincipalName,AccountEnabled,EmployeeLeaveDateTime

$targets = $users | Where-Object {
    $_.EmployeeLeaveDateTime -and
    $_.EmployeeLeaveDateTime -le $now -and
    $_.AccountEnabled -eq $true
}

$targets | Select-Object DisplayName,UserPrincipalName,AccountEnabled,EmployeeLeaveDateTime

出力結果を確認し、「想定外のユーザーが含まれていないか」「ゲスト/メンバーの区別は問題ないか」を確認してから、本番の無効化処理を有効にするようにしましょう。

権限エラー(Insufficient privileges)の対処

Update-MgUser で employeeLeaveDateTime や accountEnabled を更新する際、権限不足の場合には Authorization_RequestDenied などのエラーが返されます。

この場合、次のポイントをチェックしてみてください。

  • Graph アプリ(または接続ユーザー)に必要な権限が付与されているか
    • User.Read.All
    • User-LifeCycleInfo.ReadWrite.All
    • User.EnableDisableAccount.All
  • アプリケーション権限の場合、管理者による「管理者同意」が完了しているか
  • テナント側で「権限の付与を制限」するポリシーが有効になっていないか

Get-MgUserのプロパティ不足に注意

Get-MgUser は、何も指定しないと最小限のプロパティしか返さず、EmployeeLeaveDateTime や AccountEnabled などが含まれないことがあります。そのため、

  • -Property で必要な属性名を列挙する
  • もしくは、最初は Get-MgUser -UserId <id> -Property * -Debug などで実際にどう返ってきているか確認する

という手順をとっておくと、あとで「なぜか属性がnullになる」といった問題を避けやすくなります。

応用パターン:再有効化・削除との組み合わせ

今回紹介した仕組みは、「期限を過ぎたら無効化する」ことが主眼ですが、少し応用すると、次のようなパターンにも拡張できます。

一時的に再有効化する

「一度無効化したが、事情によりもう1週間だけ延長したい」といったケースでは、再度 employeeLeaveDateTime を更新し、accountEnabled = true に戻すだけで対応できます。

$UserId = "[email protected]"
$NewExpirationUtc = [DateTimeOffset]::UtcNow.AddDays(7)

Update-MgUser -UserId $UserId `
  -EmployeeLeaveDateTime $NewExpirationUtc `
  -AccountEnabled:$true

あとは、いつもの自動無効化バッチに任せれば、再び期限を過ぎたタイミングで自動停止されます。

一定期間後に完全削除する

ガバナンス上「無効化から90日後に完全削除したい」といった要件がある場合は、

  1. EmployeeLeaveDateTime に「契約終了日」を格納
  2. 終了日 + 〇日で accountEnabled = false(今回のスクリプト)
  3. さらに終了日 + 90日で Remove-MgUser する別バッチを用意

といった二段階の処理にすることで、「一定期間は無効アカウントとして残し、その後自動削除」というライフサイクルも実装できます(削除タイミングについては各社の規程に従ってください)。

まとめ

本記事では、Entra ID(旧Azure AD)のユーザー/ゲストに「7日後の有効期限」を持たせ、期日到来で自動的にサインイン不可にする仕組みを、Microsoft Graph PowerShell を使って構築する方法を解説しました。

  • 有効期限日は employeeLeaveDateTime 属性に格納する
  • この属性だけではアカウントは自動停止されないため、別途バッチで期限超過を検知し、accountEnabled = false に更新する
  • ゲスト(B2B)もユーザーオブジェクト(userType = Guest)なので、同じやり方で期限設定・自動無効化が可能
  • 実行環境は Windows タスク スケジューラ / Azure Automation などが使いやすく、ログ出力とドライランを組み合わせると安全に運用できる
  • Entra ID Governance を併用すれば、アカウント無効化に加え、グループ・ライセンスなどのアクセス権剥奪も自動化できる

「短期間だけ必要なアカウントを、安全に・自動的にクローズできる」仕組みは、ゼロトラスト時代のEntra ID運用において欠かせないピースです。ぜひ、employeeLeaveDateTime と簡単なPowerShellスクリプトから、身近なところでの自動化を始めてみてください。

この記事を書いた人

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

コメント

コメントする

目次