1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Entra IDユーザーを一括無効化するPowerShellスクリプト(セッション強制切断対応)

1
Posted at

はじめに

Entra ID を利用している環境において、定期的なアカウント棚卸しで未利用者を洗い出した後、それらのアカウントを無効化したい場面があります。

よくある利用シーン:

  • 退職予定者のアカウント停止
  • 長期休暇者の一時的な無効化
  • セキュリティポリシーに基づく未利用アカウントの整理

Microsoft 365管理センターのGUIでは、ユーザーの一括無効化機能が提供されていません。本記事では、PowerShellを使った安全で確実な一括無効化の方法を解説します。

関連記事: アカウント棚卸しの事前準備として、Entra IDの最終サインイン日時を一括で取得する方法もご参照ください。

無効化と削除の違い(重要)

スクリプトを実行する前に、無効化と削除の違いを理解しておくことが重要です。

無効化 (Disable)

  • サインイン不可になるが、ユーザーオブジェクトは残ります
  • メールボックス、OneDrive、ライセンスはそのまま保持されます
  • いつでも再有効化が可能です
  • 用途: 退職予定者、長期休暇者の一時的な停止

削除 (Delete)

  • 論理削除され、30日間は復元可能です
  • ライセンスは即座に解放されます
  • 30日後に完全削除されます(データも消失)
  • 用途: 完全な退職、アカウント整理

どちらを選ぶべきか

まず無効化 → 問題なければ削除、という段階的なアプローチが安全な運用です。

本記事では無効化の方法を解説します。削除については後述の補足をご確認ください。

この記事で実現できること

  • CSVからユーザーを読み込んで一括無効化
  • 無効化と同時にセッションを強制切断
  • 処理結果をTSVログで記録
  • エラーハンドリングと進捗表示

前提条件

  • Microsoft.Graph PowerShellモジュール(v2.x以降)
  • グローバル管理者またはユーザー管理者権限

モジュールの確認とインストール

# バージョン確認
Get-Module Microsoft.Graph -ListAvailable

# インストール(必要な場合)
Install-Module Microsoft.Graph -Scope CurrentUser

# v1.xからのアップデート
Update-Module Microsoft.Graph

実行前の確認事項

影響範囲の理解

  • 無効化されたユーザーは即座にサインイン不可になります
  • 共有メールボックスの代理アクセス権限なども失効します
  • Microsoft Teams、SharePointでの活動も利用できなくなります

テスト実行の推奨

本番環境で実行する前に、以下を推奨します:

  1. テストユーザー1名でスクリプトを試す
  2. $DoSignout = $false で動作確認する
  3. ログファイルの出力形式を確認する

準備:CSVファイルの作成

以下の形式でCSVファイルを作成します。

UserPrincipalName
user1@contoso.com
user2@contoso.com

重要:

  • ヘッダー行は必ず UserPrincipalName としてください
  • 文字コードはUTF-8を推奨します
  • Excelで作成する場合、「CSV UTF-8 (コンマ区切り) (*.csv)」形式で保存してください

スクリプト全文

# 0) Graph に接続
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
Connect-MgGraph -Scopes "User.ReadWrite.All"

# 1) セッション無効化関数
function Revoke-Sessions {
    param(
        [Parameter(Mandatory=$true)][string]$UserId,
        [Parameter(Mandatory=$true)][bool]$DoSignout
    )
    if (-not $DoSignout) { return }
    try {
        # Microsoft.Graph 2.x 以降の標準コマンド
        if (Get-Command Revoke-MgUserSignInSession -ErrorAction SilentlyContinue) {
            Revoke-MgUserSignInSession -UserId $UserId -ErrorAction Stop | Out-Null
            Write-Host "  → セッション無効化完了" -ForegroundColor Gray
        } else {
            Write-Host "  → セッション無効化コマンドが見つかりません(スキップ)" -ForegroundColor Yellow
        }
    } catch {
        Write-Host "  → セッション無効化失敗: $($_.Exception.Message)" -ForegroundColor Yellow
    }
}

# 2) 設定
$CsvPath   = ".\disable_users.csv"
$DoSignout = $true

# 3) ログ準備
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$logPath   = ".\disable_users_result_$timestamp.tsv"
"UserPrincipalName`tResult`tMessage" | Out-File -FilePath $logPath -Encoding UTF8

# 4) CSV存在確認・読込
if (-not (Test-Path $CsvPath)) {
    Write-Host "CSV が見つかりません: $CsvPath" -ForegroundColor Red
    exit 1
}

$users = Import-Csv -Path $CsvPath

if ($users.Count -eq 0) {
    Write-Host "CSV にデータがありません" -ForegroundColor Red
    exit 1
}

if (-not ($users[0].PSObject.Properties.Name -contains "UserPrincipalName")) {
    Write-Host "CSV に 'UserPrincipalName' 列が見つかりません" -ForegroundColor Red
    exit 1
}

# 5) 確認プロンプト
Write-Host "`n【警告】$($users.Count) 件のユーザーを無効化します" -ForegroundColor Yellow
$confirm = Read-Host "続行しますか? (y/n)"
if ($confirm -notmatch '^y(es)?$') {
    Write-Host "キャンセルしました" -ForegroundColor Cyan
    exit 0
}

# 6) 実行ループ
$total = $users.Count
$current = 0
$successCount = 0
$failCount = 0

foreach ($u in $users) {
    $current++
    Write-Progress -Activity "ユーザー無効化処理" -Status "$current / $total" -PercentComplete (($current/$total)*100)
    
    $upn = $u.UserPrincipalName.Trim()
    if ([string]::IsNullOrWhiteSpace($upn)) {
        Write-Host "[$current/$total] スキップ:空の UPN 行" -ForegroundColor Yellow
        "$upn`tSkip`tBlank UPN" | Out-File -FilePath $logPath -Append -Encoding UTF8
        continue
    }
    
    try {
        # ユーザー取得
        $userObj = Get-MgUser -UserId $upn -ErrorAction Stop
        
        # ゲストユーザーの警告表示(オプション)
        if ($userObj.UserType -eq "Guest") {
            Write-Host "  ⚠ Warning: $upn はゲストユーザーです" -ForegroundColor Yellow
        }
        
        # 無効化
        Update-MgUser -UserId $userObj.Id -AccountEnabled:$false -ErrorAction Stop
        
        # セッション無効化
        Revoke-Sessions -UserId $userObj.Id -DoSignout $DoSignout
        
        Write-Host "[$current/$total] ✓ Disabled: $upn" -ForegroundColor Green
        "$upn`tSuccess`tDisabled" | Out-File -FilePath $logPath -Append -Encoding UTF8
        $successCount++
        
    } catch {
        $msg = ($_.Exception.Message -replace "`t"," " -replace "`r`n"," ").Substring(0, [Math]::Min(200, $_.Exception.Message.Length))
        Write-Host "[$current/$total] ✗ Failed: $upn - $msg" -ForegroundColor Red
        "$upn`tFailed`t$msg" | Out-File -FilePath $logPath -Append -Encoding UTF8
        $failCount++
    }
}

Write-Progress -Activity "ユーザー無効化処理" -Completed

# 7) サマリー表示
Write-Host "`n========== 処理完了 ==========" -ForegroundColor Cyan
Write-Host "成功: $successCount 件" -ForegroundColor Green
Write-Host "失敗: $failCount 件" -ForegroundColor Red
Write-Host "結果ログ: $logPath" -ForegroundColor Cyan

使い方

  1. CSVファイルを準備します
  2. スクリプトを実行します
  3. 確認プロンプトで "yes" を入力します
  4. 結果ログを確認します
  5. 接続解除 (オプション)
Disconnect-MgGraph

注意点

セッション無効化について

AccountEnabled:$false だけでは既存セッションが残り続けます。Revoke-MgUserSignInSession による強制ログアウトを推奨します。

理由:

  • 無効化されたユーザーでも、既存のアクセストークンが有効期限内であれば一部のサービスにアクセス可能な場合があります
  • セッション無効化により、すべてのアクティブなセッションが即座に切断されます

ログファイルについて

結果ログ(TSV形式)には以下の情報が記録されます:

  • UserPrincipalName: 対象ユーザー
  • Result: Success / Failed / Skip
  • Message: 処理結果の詳細

トラブルシューティング

"Insufficient privileges" エラー

原因: 必要な権限が不足しています。

対処法: User.ReadWrite.All 権限でGraph APIに接続してください。

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

セッション無効化がスキップされる

原因: Microsoft.Graph v2.x未満のバージョンを使用しています。

対処法: Microsoft.Graph v2.x以降に更新してください。

Update-Module Microsoft.Graph

CSV読み込みエラー

原因: CSVファイルの形式が正しくありません。

対処法:

  • ヘッダー行が UserPrincipalName になっているか確認してください
  • 文字コードがUTF-8になっているか確認してください
  • Excelで開いて余分な空行がないか確認してください

補足: ユーザーを一括削除する場合

無効化ではなく削除したい場合は、以下のように変更します:

# 無効化の代わりに削除
Remove-MgUser -UserId $userObj.Id -ErrorAction Stop

# セッション無効化は不要(削除時は自動的に切断される)

注意事項:

  • 削除されたユーザーは30日後に完全削除されます
  • ライセンスは即座に解放されます
  • 慎重に実行してください

推奨: まず無効化で運用し、問題がなければ削除する段階的なアプローチをお勧めします。

まとめ

GUIでは実現できない一括無効化を、安全かつ監査可能な形で実装できました。

ポイント:

  • CSVベースでの一括処理により、作業効率が大幅に向上します
  • セッション無効化により、セキュリティリスクを最小化できます
  • 結果ログ(TSV形式)により、監査証跡を残すことができます

アカウント棚卸しの事前準備として、Entra IDの最終サインイン日時を一括で取得する方法と組み合わせることで、より効率的な運用が可能になります。

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?