みなさんこんにちは!ヒロポンです!
「新人30人分のADアカウント、今日中に作っといて」
朝礼でこれ言われた時、業務SEは何を思いますか??
俺なら血の気が引きます…!!だってGUIでポチポチやると、1人あたり3-4分。30人なら2時間コース。しかも初期パスワード設定とか、OUパス選択とか、毎回ミスる罠が散らばってる。
で、これPowerShellで書いたら5分で終わります。マジで。
今回は業務SEが初めてADバルク登録に挑む時の、CSV → Import-Csv → New-ADUserの実戦パターンをまとめていきます。Docker検証で実走したターミナルキャプチャも貼ります。
忙しい人向けに最初にまとめ
- 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つあります。

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 / catchで1人失敗しても残り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
}
実行結果:

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)]"
}
実行結果:

ハッシュテーブルに詰め込んだ引数が、そのまま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 UTF8はBOM付き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に落とす運用を推奨します。
関連記事
- 業務イントラの認証— Windows認証/ Forms認証/ Cookieの使い分けで業務SEが踏む選択 — ADと絡む業務系認証パターンの整理
以上!
執筆者
バイブス父さん — 業務 SE 7 年 (正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SES 複数社・フリーランスエージェント複数経由の経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。
🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る


コメント