業務SE が初めて触る AD バルクユーザー作成 — PowerShell で30人を5分で登録するスクリプト

みなさんこんにちは!ヒロポンです!

「新人30人分の AD アカウント、今日中に作っといて」

朝礼でこれ言われた時、業務SE は何を思いますか??

俺なら 血の気が引きます…!! だって GUI でポチポチやると、1人あたり3-4分。30人なら2時間コース。しかも初期パスワード設定とか、OU パス選択とか、毎回ミスる罠が散らばってる。

で、これ PowerShell で書いたら 5分で終わります。マジで。

今回は業務SE が初めて AD バルク登録に挑む時の、CSV → Import-CsvNew-ADUser の実戦パターンをまとめていきます。Docker 検証で実走したターミナルキャプチャも貼ります。

目次

TL;DR

  • CSV に30人分の情報を並べて、Import-Csv | ForEach-Object { New-ADUser @params } で一気に登録できる
  • GUI なら2時間、PowerShell なら5分。dsadd.exe という第三の選択肢もあるが、可読性と再実行性で PowerShell に収束する
  • ハマりポイントは パスワード complexity・OU パス順序・SamAccountName 重複・PowerShell 5.1 vs 7 のエンコーディング差。後半でぜんぶ潰します

3つのバルク登録手段を最初に並べる

業務SE が AD アカウントを大量に作る手段は、ざっくり3つあります。

AD ユーザー一括登録 — 3手段の観点別比較表

PowerShell が「コードを残せる・再実行できる・エラーが出た行を追える」で、結局これに収束します。

dsadd.exe はレガシーで CSV を直接食えないため、結局ループを書く時点で PowerShell と差が出ない。GUI は1人なら速いけど、30人やる気力は俺には無い。

で、今回の主役は PowerShell です。

Step 1: CSV を設計する

users.csv をこんな感じで用意します。列は最低限これだけ。

GivenName,Surname,SamAccountName,UPN,OU,Password
太郎,山田,t.yamada,t.yamada@example.local,"OU=営業部,OU=Users,DC=example,DC=local",P@ssw0rd!Init2026
花子,鈴木,h.suzuki,h.suzuki@example.local,"OU=営業部,OU=Users,DC=example,DC=local",P@ssw0rd!Init2026
次郎,佐藤,j.sato,j.sato@example.local,"OU=技術部,OU=Users,DC=example,DC=local",P@ssw0rd!Init2026

ポイントは3つ。

  • UPN (UserPrincipalName): samaccount@ドメイン.local の形。Microsoft 365 と連携する現場ならここがログインIDになる
  • OU パス: OU=営業部,OU=Users,DC=example,DC=local の DN 形式。末端から書く のがハマりポイント
  • Password: ドメインのパスワード複雑性ポリシーを満たすこと。大小英字+数字+記号

CSV は UTF-8 with BOM で保存します。BOM 無しだと PowerShell 5.1 で文字化けする罠があります。

Step 2: Import-Csv + ForEach-Object + New-ADUser

ここが本丸。こんな感じで一気に貼ります。

Import-Csv -Path 'users.csv' -Encoding UTF8 | ForEach-Object {
    $params = @{
        Name                  = "$($_.GivenName) $($_.Surname)"
        GivenName             = $_.GivenName
        Surname               = $_.Surname
        SamAccountName        = $_.SamAccountName
        UserPrincipalName     = $_.UPN
        Path                  = $_.OU
        AccountPassword       = (ConvertTo-SecureString -AsPlainText $_.Password -Force)
        Enabled               = $true
        ChangePasswordAtLogon = $true
    }
    try {
        New-ADUser @params
        Write-Host "OK: $($_.SamAccountName)" -ForegroundColor Green
    } catch {
        Write-Host "NG: $($_.SamAccountName) - $($_.Exception.Message)" -ForegroundColor Red
    }
}

@params の書き方は スプラッティング という PowerShell の技。ハッシュテーブルに引数を全部詰めて、 @ プレフィックスで cmdlet に渡せる。

正直、最初に見た時は「は??」ってなったんですけど、慣れるとめちゃくちゃ便利。引数が10個超える cmdlet を、1行のバックスラッシュ地獄から救ってくれます。

try / catch1人失敗しても残り29人は通る ようにしてるのも地味に効きます。業務系のバルク処理は「全件 or ゼロ」じゃなく「成功分は通す・失敗分は後でやり直し」が現場の正解。

Step 3: Docker container で言語仕様部分を動作確認

実環境の AD に流す前に、PowerShell 7 で 言語仕様部分だけ Docker で動かして確認しときます。

ActiveDirectory モジュールは Windows Server の RSAT 抜きだと入らないので、Linux container では New-ADUser 自体は呼べません。

代わりに ConvertFrom-Csv でメモリ上の CSV をパースして、各レコードを PSCustomObject に組み立てる 構造化部分 を検証します。

$csvText = @"
GivenName,Surname,SamAccountName
太郎,山田,t.yamada
花子,鈴木,h.suzuki
次郎,佐藤,j.sato
"@

$csvText | ConvertFrom-Csv | ForEach-Object {
    $user = [PSCustomObject]@{
        Name           = "$($_.GivenName) $($_.Surname)"
        SamAccountName = $_.SamAccountName
        Status         = "Created (mock)"
    }
    $user | ConvertTo-Json -Compress
}

実行結果:

ConvertFrom-Csv + PSCustomObject の実行結果 (verify-pwsh container)

CSV を3件パースして、各 user オブジェクトが JSON で出てきてます。日本語マルチバイトもそのまま通った。これが Step 2 の New-ADUser @params 直前までの動作を保証する 入力検証層 になります。

続いて、スプラッティング (@params) の引数組み立て部分も検証しときます。

$users = @"
GivenName,Surname,SamAccountName,UPN
太郎,山田,t.yamada,t.yamada@example.local
花子,鈴木,h.suzuki,h.suzuki@example.local
"@ | ConvertFrom-Csv

$users | ForEach-Object {
    $params = @{
        Name              = "$($_.GivenName) $($_.Surname)"
        GivenName         = $_.GivenName
        Surname           = $_.Surname
        SamAccountName    = $_.SamAccountName
        UserPrincipalName = $_.UPN
    }
    Write-Host "Created: $($params.Name) ($($params.SamAccountName)) [$($params.UserPrincipalName)]"
}

実行結果:

スプラッティング (@params) の引数組み立て検証

ハッシュテーブルに詰め込んだ引数が、そのまま Write-Host 側に展開されてるのが確認できる。本番では Write-Host の代わりに New-ADUser @params を置けば、 そのまま実環境に流せます。

実環境への流し込みは Domain Controller 側でしかできないので、残りは Get-ADUser で事後確認すれば OK です。

ハマりポイント4選 (現場で踏みがちなやつ)

ここからが今回の本題かもしれない。業務SE が踏みがちな罠を4つ。

① パスワード complexity 要件で全件失敗

ドメインのデフォルトポリシーは以下のいずれかを満たす必要があります。

  • 8文字以上
  • 大文字・小文字・数字・記号のうち3種類以上を含む

P@ssw0rd! みたいなテンプレならOK。 でも Pass2026 みたいな 記号無し で投げると、全件 The password does not meet the password policy requirements で死にます。

俺もこれで、ある日のバルク登録30件が全部 NG になって、軽く絶望した記憶があります。CSV の Password 列、 投入前にざっと目で見るだけで防げる事故です。

② OU パスを逆順で書く

OU パスは DN 形式で、末端から書きます

OU=営業部,OU=Users,DC=example,DC=local  # ✅ 正しい
DC=example,DC=local,OU=Users,OU=営業部  # ❌ 順序が逆

逆に書くと The object name has bad syntax で失敗。「DC=local が一番うしろ」と覚えると間違えにくい。

ちなみに OU 名に日本語使ってる現場は普通にあって、その場合 CSV ダブルクオート囲み必須です。

③ SamAccountName が20文字を超えてる

SamAccountName は 20文字制限 があります。taro.yamada.from.sales みたいに長い名前を投げると、cmdlet が黙って切り捨てたり、失敗したりする。

新人の名簿が長い場合は、CSV 投入前に検証しときましょう。

Import-Csv users.csv | Where-Object { $_.SamAccountName.Length -gt 20 }

ヒット行があればそこだけ修正。これで投入後の事故が半分は減ります。

④ PowerShell 5.1 と 7 のエンコーディング差

Import-Csv -Encoding UTF8 の挙動は 5.1 と 7 で微妙に違います。

  • 5.1: -Encoding UTF8BOM 付き UTF-8 前提。BOM 無し CSV だと文字化け
  • 7: BOM 有無を自動判定してくれる

ドメインコントローラが Windows Server 2016 で PowerShell 5.1 のまま、ってのは業務系の現場で普通にあるパターン。 ここを踏んで「文字化けでユーザー名が ??? になった」 のはあるあるです。

CSV は BOM 付きで保存する習慣 をつけときましょう。VS Code なら右下のエンコーディング表示クリックで UTF-8 with BOM に切り替えできます。

まとめ

GUI で 30人 = 2時間。PowerShell なら 5分。CSV を整える時間を入れても 30分以内です。

書いたスクリプトは同じドメインなら使い回せるし、翌年の新人受け入れでも users.csv を差し替えるだけで動く。これがコード資産化のうま味なんですよね。

業務SE 1人運用で AD 触る現場って、 そんなにベテランがいないことが多くて、 「PowerShell? あの黒い画面でしょ?」 で止まってる人が多い。 でも1個書き上げると、 俺の業務時間が 明らかに浮きます!!

ぶっちゃけ、 月1の定例登録作業は ぜんぶスクリプト化して、 「実行して結果見るだけ」 に変えるのがゴール。 そこまで持っていけば、 翌月以降の俺が いい感じに 楽できます。

動作確認メモ: 今回のスクリプトは PowerShell 7 言語仕様レベルで Linux container 検証済。 ただし New-ADUser 本体は Windows RSAT (ActiveDirectory モジュール) が前提のため、 実際の登録は Windows ドメインコントローラ または RSAT 入り運用端末 で実行してください。 CSV パース・スプラッティング部分はそのままコピペで動きます。

よくある質問

Q1. PowerShell ISE と Visual Studio Code、どっちで書くべき?

A. VS Code 一択 です。 ISE は新規開発が止まっていて、 PowerShell 7 に対応してない。 VS Code + PowerShell 拡張機能で、 IntelliSense もデバッグも一通り揃います。 業務系の現場でも VS Code は普及してきてるので、入れて損は無いです。

Q2. ActiveDirectory モジュールが入ってないサーバーでは?

A. RSAT (Remote Server Administration Tools) を追加する必要があります。 Windows Server なら役割追加から、 Windows 10/11 クライアントなら設定 > オプション機能 から RSAT をインストール。 これ無いと New-ADUser が無い世界です。 普段使い PC で AD 管理する場合も RSAT を入れます。

Q3. CSV じゃなくて Excel から直接やりたいんですが

A. ImportExcel モジュールを使えば xlsx をそのまま読めます。 Install-Module ImportExcel -Scope CurrentUser で入る。 ただ業務的には CSV 経由が監査ログ的に楽 で、 差分が見やすい・テキスト diff が効く・Git で履歴管理もできる、 という利点があります。 一度 CSV に落とす運用を推奨します。

関連記事

以上!


この記事が気に入ったら
いいねしてね!

どんどんシェア待ってるぜ!!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次