Active DirectoryのextensionAttribute1でユーザー区分ごとの日次自動処理を行うPowerShellスクリプト構築ガイド

Active Directory のユーザーごとに設定している extensionAttribute1 を使うと、「CW」「Regular」「SP」などの区分に応じた処理を自動化できます。本記事では、PowerShell とタスク スケジューラを組み合わせて、extensionAttribute1 をキーにした日次バッチを構築する具体的な手順とサンプル スクリプト、運用のベストプラクティスまでまとめて解説します。

目次

extensionAttribute1 を使ったユーザー自動処理の全体像

まずは、実現したいことを整理します。

  • Active Directory ユーザー オブジェクトに既に設定している extensionAttribute1 を利用する
  • CW / Regular / SP などの値ごとに処理内容を分岐する
  • extensionAttribute1 が空のユーザーは対象外にする
  • PowerShell スクリプトを Windows タスク スケジューラで毎日自動実行する

構成イメージは以下のようになります。

フェーズ処理内容担当
1. ユーザー抽出extensionAttribute1 が空でない AD ユーザーを Get-ADUser で取得PowerShell
2. 値ごとの分岐switch 文で CW / Regular / SP など値ごとに処理を分岐PowerShell
3. 任意の操作Set-ADUser / グループ操作 / ライセンス更新 / 無効化などを実行PowerShell
4. 自動実行タスク スケジューラから毎日決まった時間にスクリプトを起動Windows タスク スケジューラ

この仕組みを一度作っておけば、extensionAttribute1 の値を変えるだけで、ユーザー区分に応じた処理内容を運用側でコントロールできるようになります。

extensionAttribute1 の値設計のポイント

extensionAttribute1 は「どういう区分を表すのか」を最初にきちんと決めておくと、後からスクリプトを拡張しやすくなります。よくある例を整理すると以下のようになります。

想定される意味代表的な処理例
CW派遣・委託・契約社員 (Contract Worker)特定グループへの所属、アクセス制限、契約終了日近辺での無効化
Regular正社員・常勤標準グループへの追加、メールボックスやライセンス付与、MFA 必須化など
SP協力会社アカウント・スポット利用利用期限のチェック、夜間ログオン制御、一定期間での無効化や削除
その他 (例:Temp)短期利用アカウント、テスト用など期限付きの有効化、検証用 OU への移動など

記事内のサンプルでは CW / Regular / SP の 3 パターンを例に説明しますが、実際の運用では組織に合わせて値を増減させて構いません。

基本の PowerShell スクリプト例

まずは、できるだけシンプルにした「基本形」のスクリプトです。extensionAttribute1 が空でない全ユーザーを取得し、値ごとの処理を切り替える構造になっています。

# Active Directory モジュールを読み込む
Import-Module ActiveDirectory

# extensionAttribute1 が設定されているユーザーを取得
$users = Get-ADUser -Filter 'extensionAttribute1 -like "*"' `
                    -Properties extensionAttribute1,SamAccountName

# 値ごとに分岐して処理
foreach ($user in $users) {
    switch ($user.extensionAttribute1) {

        "CW" {
            Write-Output "CW ロジック実行: $($user.SamAccountName)"
            # 例: Set-ADUser -Identity $user -Replace @{extensionAttribute1 = "CW"}
        }

        "Regular" {
            Write-Output "Regular ロジック実行: $($user.SamAccountName)"
            # 例: 標準グループへの追加
            # Add-ADGroupMember -Identity "GG_Employees" -Members $user
        }

        "SP" {
            Write-Output "SP ロジック実行: $($user.SamAccountName)"
            # 例: アカウント無効化
            # Disable-ADAccount -Identity $user
        }

        default {
            Write-Output "未定義の値 $($user.extensionAttribute1) – スキップ: $($user.SamAccountName)"
        }
    }
}

上記のスクリプトは、コメント部分を書き換えるだけでそのまま運用に流用できます。重要なのは以下の 3 点です。

  • -Filter 'extensionAttribute1 -like "*"' により「空でないユーザーのみ」をサーバー側でフィルタしている
  • switch 文で値ごとに処理をきれいに分けている
  • default 節で「想定外の値」をログに出して気づけるようにしている

対象 OU を絞り込みたい場合

「すべてのユーザー」ではなく特定 OU 配下だけを対象にしたい場合は、-SearchBase を追加します。

$searchBase = "OU=Users,OU=Tokyo,DC=contoso,DC=local"

$users = Get-ADUser -Filter 'extensionAttribute1 -like "*"' `
                    -SearchBase $searchBase `
                    -Properties extensionAttribute1,SamAccountName

大規模環境ではこのように OU 単位で対象を絞ることで、パフォーマンスと安全性の両方を確保できます。

運用に耐える「強化版」スクリプト

実際の本番運用では、最低限次の要素を追加しておくことをおすすめします。

  • ログ出力(いつ誰に何をしたかを記録)
  • エラーハンドリング(1 ユーザーで失敗しても全体が止まらないように)
  • Strict モードの有効化(変数のタイプミスに早く気づく)
  • パラメーター化(OU やログパスを外から指定できるようにする)

これらを組み込んだサンプルが次のスクリプトです。

param(
    [string]$SearchBase = "OU=Users,DC=contoso,DC=local",
    [string]$LogPath    = "\\server\logs\AdAttributeDaily.log"
)

Import-Module ActiveDirectory
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# ログ出力用の関数
function Write-Log {
    param(
        [string]$Message,
        [string]$Level = "INFO"
    )

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $line      = "{0} [{1}] {2}" -f $timestamp, $Level, $Message
    Write-Output $line
    Add-Content -Path $LogPath -Value $line
}

Write-Log "========== extensionAttribute1 日次処理開始 =========="

try {
    $filter = 'extensionAttribute1 -like "*"'
    $props  = @("samAccountName","userPrincipalName","extensionAttribute1")

    Write-Log "SearchBase: $SearchBase / Filter: $filter"

    $users = Get-ADUser -Filter $filter -SearchBase $SearchBase -Properties $props

    Write-Log "対象ユーザー数: $($users.Count)"

    foreach ($user in $users) {

        $sam  = $user.SamAccountName
        $attr = $user.extensionAttribute1

        try {
            switch ($attr) {

                "CW" {
                    Write-Log "CW ロジック開始: $sam"
                    # 例: 契約社員用グループへの追加
                    # Add-ADGroupMember -Identity "GG_ContractWorker" -Members $user -WhatIf
                    Write-Log "CW ロジック完了: $sam"
                }

                "Regular" {
                    Write-Log "Regular ロジック開始: $sam"
                    # 例: 標準グループへの追加、ライセンス用属性の更新など
                    # Set-ADUser -Identity $user -Replace @{extensionAttribute2 = "Employee"} -WhatIf
                    Write-Log "Regular ロジック完了: $sam"
                }

                "SP" {
                    Write-Log "SP ロジック開始: $sam"
                    # 例: アカウント無効化や特定グループからの除外
                    # Disable-ADAccount -Identity $user -WhatIf
                    Write-Log "SP ロジック完了: $sam"
                }

                default {
                    Write-Log "未定義の値 [$attr] - スキップ: $sam" "WARN"
                }
            }
        }
        catch {
            Write-Log "ユーザー [$sam] の処理でエラー: $($_.Exception.Message)" "ERROR"
        }
    }
}
catch {
    Write-Log "スクリプト全体で致命的なエラー: $($_.Exception.Message)" "ERROR"
}

Write-Log "========== extensionAttribute1 日次処理終了 =========="

上記のサンプルでは、実際の変更系コマンドには -WhatIf を付けたコメントにしています。本番に投入する前は必ず -WhatIf を残した状態でテスト OU で検証し、問題なければ -WhatIf を外す、という流れを推奨します。

ログの確認と活用例

ログ出力を行っておくと、次のような分析が可能になります。

  • 前日と比べて処理対象ユーザー数が異常に増えていないか
  • 特定の値(例:SP)のユーザーだけエラーが多発していないか
  • 未定義の値(default 節)が頻繁に出ていないか(入力ミスの早期発見)

たとえば以下のような形式であれば、Excel に取り込んでピボット分析することも簡単です。

日時レベルメッセージ例
2025-01-01 01:00:05INFO対象ユーザー数: 1234
2025-01-01 01:00:10INFOCW ロジック開始: yamada_taro
2025-01-01 01:00:11ERRORユーザー [suzuki_hanako] の処理でエラー: Access is denied

タスク スケジューラで日次自動実行する手順

スクリプトができたら、Windows タスク スケジューラで「毎日自動実行」の設定を行います。

スクリプトの配置

  • 例: \\server\scripts\AdAttributeDaily.ps1 に保存
  • タスク実行用サービス アカウントに対して読み取り権限を付与
  • ログ出力先フォルダー(例: \\server\logs)にも書き込み権限を付与

タスクの作成

  1. 管理者権限で「タスク スケジューラ」を起動
  2. 「タスクの作成」をクリック
  3. 「全般」タブで以下を設定
    • 名前:AD extensionAttribute1 日次処理 などわかりやすいもの
    • 「最上位の特権で実行する」にチェック
    • 「構成する対象」を実行中の OS に合わせて選択
    • 実行アカウント:必要な権限を持つドメインのサービス アカウント
  4. 「トリガー」タブで「新規」をクリック
    • タスクの開始:スケジュールに従う
    • 設定:毎日
    • 開始時刻:夜間や業務時間外など、処理に負荷がかかっても問題ない時間帯
  5. 「操作」タブで「新規」をクリックし、以下のように設定
    • 操作:プログラムの開始
    • プログラム/スクリプト:powershell.exe
    • 引数の追加(オプション):
    -NoProfile -ExecutionPolicy Bypass -File "\\server\scripts\AdAttributeDaily.ps1"
    • 開始(オプション):空欄で OK(必要に応じてスクリプト格納フォルダー)
  6. 「条件」「設定」タブで、サーバー状況に合わせて電源や再試行の設定を調整

設定後は「今すぐ実行」で一度手動実行し、ログが正しく出力されているか、エラーが出ていないかを確認しておきましょう。

安全なテスト手順とベストプラクティス

Active Directory を変更するスクリプトは、本番投入前のテストが非常に重要です。代表的なベストプラクティスを整理します。

ステップやることポイント
1. テスト OU で検証本番と同等のテスト OU を作り、一部ユーザーをコピーまたはテストユーザーで再現するテスト OU を SearchBase に指定して、まずは限定的に動かす
2. -WhatIf モード変更系コマンドに -WhatIf を付けた状態で動作を確認どのユーザーにどんな変更が加わるかをログで詳細に確認できる
3. ログ確認ログの行数と対象ユーザー数、エラー行の有無をチェック「対象ユーザー数 = 実際の対象ユーザー数」になっているかを照合
4. 本番 OU への展開SearchBase を本番 OU に変え、最初は限定的なサブ OU から開始段階的に範囲を広げることでリスクを低減
5. 完全自動化タスク スケジューラで毎日(日次/週次)の自動実行に切り替え初期はログを毎日チェックし、安定後は週次チェックへ移行

また、スクリプトの先頭で Set-StrictMode -Version Latest を有効にしておくと、変数名のタイプミスなどを早期に検知でき、運用中の思わぬバグを減らすことができます。

extensionAttribute1 を「マスターデータ」のように使う設計

スクリプトの switch に処理ロジックを書きすぎると、後からの変更が難しくなります。そこで、extensionAttribute1 の値と処理内容の対応を、CSV や JSON などの「外部マスターファイル」で管理する方法も有効です。

例として、次のような CSV ファイルを用意します。

Value,GroupToAdd,DisableAccount
CW,GG_ContractWorker,False
Regular,GG_Employees,False
SP,,True

この CSV を読み込み、値ごとにグループ追加や無効化フラグを変えるサンプルを示します。

$configPath = "\\server\scripts\ExtensionAttr1Config.csv"
$configs    = Import-Csv -Path $configPath

# extensionAttribute1 → 設定オブジェクト のハッシュテーブルを作成
$map = @{}
foreach ($c in $configs) {
    $map[$c.Value] = $c
}

foreach ($user in $users) {
    $sam  = $user.SamAccountName
    $attr = $user.extensionAttribute1

    if (-not $map.ContainsKey($attr)) {
        Write-Log "設定ファイルに存在しない値 [$attr] - スキップ: $sam" "WARN"
        continue
    }

    $config = $map[$attr]
    Write-Log "[$attr] 設定に従い処理開始: $sam"

    if ($config.GroupToAdd) {
        # Add-ADGroupMember -Identity $config.GroupToAdd -Members $user -WhatIf
        Write-Log "グループ [$($config.GroupToAdd)] に追加予定: $sam"
    }

    if ([bool]::Parse($config.DisableAccount)) {
        # Disable-ADAccount -Identity $user -WhatIf
        Write-Log "アカウント無効化予定: $sam"
    }

    Write-Log "[$attr] 設定に従う処理完了: $sam"
}

このように「値と処理の対応関係」を外部ファイル化しておくと、運用サイドが CSV を編集するだけでロジックを変更できるため、スクリプト自体の改修頻度を下げられます。

権限設計とセキュリティ上の注意点

extensionAttribute1 を元に AD オブジェクトを変更する以上、権限周りの設計も重要です。次の点を意識しておきましょう。

  • タスク実行用サービス アカウントは「最小権限の原則」で必要な権限だけを付与する
  • できれば専用 OU に対してのみ書き込み権限を付与し、他 OU への影響を制限する
  • スクリプトはアクセス制御された共有フォルダーに保存し、改ざんされないようにする
  • 可能であれば PowerShell スクリプトの署名(コードサイニング)を検討する
  • ログには機密情報(パスワードなど)を絶対に出力しない

特に、タスク スケジューラ実行アカウントにドメイン管理者権限を与えるのは最終手段であり、可能ならば対象 OU のみを操作できる「限定的な管理者アカウント」にとどめるのが理想です。

よくあるトラブルと対処方法

実際に運用していると、次のようなトラブルが発生しがちです。代表例と対処方法を簡単にまとめます。

症状原因の例対処方法
タスク スケジューラ上は「実行完了」なのに何も処理されていない-ExecutionPolicy Bypass を付け忘れ、スクリプトがブロックされているタスクの「引数」に -ExecutionPolicy Bypass を追加し、ログを出力して内容を確認
特定ユーザーだけエラーになる権限不足、OU 移動済みで SearchBase から外れている、属性が想定外の値ログに出ている SamAccountName / DN をもとに、ADUC で実際の状態を確認する
処理時間がどんどん長くなってきた対象ユーザー数の増加 / Filter が緩すぎて不要なユーザーまで取得しているSearchBase で OU を絞る、extensionAttribute1 の値パターンを見直す
「未定義の値」のログが大量に出ているextensionAttribute1 の入力ルールが徹底されていない入力プロセスを見直し、マスター値の一覧を周知する。または CSV マスター方式に変更する

まとめ:extensionAttribute1 を軸にした AD 自動化のメリット

本記事では、Active Directory ユーザーの extensionAttribute1 を使って、日次の自動スクリプトを構築する方法を解説しました。

  • extensionAttribute1 に「ユーザー区分」や「契約形態」を入れておくことで、後から一括処理しやすくなる
  • PowerShell の Get-ADUserswitch を組み合わせることで、値ごとの処理をシンプルに実現できる
  • ログ出力やエラーハンドリングを加えることで、運用中のトラブルシューティングが容易になる
  • タスク スケジューラに登録すれば、完全自動の「夜間バッチ」として毎日動かせる
  • 処理ロジックを CSV などで外部化すると、運用担当者だけでも柔軟にルール変更が可能になる

「ユーザーに手作業でグループを付けたり外したりしている」「契約社員の無効化漏れが心配」といった課題がある環境では、extensionAttribute1 を軸にしたこの仕組みが大きな助けになります。まずはテスト OU から、少しずつ自動化の範囲を広げてみてください。

この記事を書いた人

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

コメント

コメントする

目次