PowerShellでローカル管理者追加を自動化するなら、Add-LocalGroupMember をそのまま流すだけでは不十分です。Administrators グループに入ったアカウントは端末へのフルコントロールを持つため、名前の取り違えやログ不足がそのまま権限事故になります。Microsoft も Administrators のメンバーは絞るよう案内しています。(Microsoft Learn)
安全に進めるコツは4つだけです。追加先の Administrators を SID で特定する、対象アカウントを曖昧にしない、追加前に存在確認して冪等化する、戻し方とログを先に作る。この記事では、PowerShellでローカル管理者追加を安全に自動化する最小手順から、実運用向けスクリプト、GPO・Intune・LAPS・JEA を使い分ける判断基準まで、すぐ実践できる形で整理します。(Microsoft Learn)
PowerShellでローカル管理者追加を安全に自動化する判断基準
| 観点 | 安全側の選び方 | 実務上の意味 |
|---|---|---|
| 追加対象 | 個人ユーザーより管理用グループ | 付与と回収を人ではなくグループ単位で管理しやすい |
| 追加先の指定 | Administrators を名前で決め打ちせず SID で扱う | 名前依存を減らし、スクリプトを環境差分に強くできる |
| 実行方式 | 追加前確認つきの冪等スクリプト | 何度流しても壊れにくい |
| 証跡 | Transcript か中央ログを残す | だれをいつ追加したか追跡しやすい |
| 多数端末 | PowerShell単発より GPO / Intune を優先 | 端末ごとのばらつきを減らしやすい |
この判断は、Add-LocalGroupMember がローカルグループへユーザーやグループを追加でき、Administrators メンバーに大きな権限があること、組み込み Administrators グループが well-known SID S-1-5-32-544 を持つこと、Get-LocalGroupMember や Add-LocalGroupMember が SID 指定に対応すること、Start-Transcript でコマンドと出力を記録できること、さらに GPO / Intune がローカルグループ管理を集中化できることに基づいています。(Microsoft Learn)
先に押さえたい前提条件と落とし穴
LocalAccounts モジュールは、64ビット OS 上の 32ビット PowerShell では利用できません。古い管理ツールや x86 エージェントからスクリプトを起動していると、Add-LocalGroupMember 自体が見つからないことがあります。自動化の前に、対象ホストで 64ビット PowerShell が使われているかを確認してください。(Microsoft Learn)
ドメイン参加 PC では、ローカルユーザーと同名のドメインメンバーがいる状態で追加を試すと、ローカルではなくドメイン側が追加されます。Admin01 のような曖昧な指定は避け、CONTOSO\Helpdesk-LocalAdmins や $env:COMPUTERNAME\BreakGlassAdmin のように完全修飾名で扱うのが安全です。(Microsoft Learn)
確認結果で PrincipalSource を見て、ローカルなのか Active Directory なのか Microsoft Entra なのかを判別する運用は有効です。ただし、このプロパティは Windows 10 / Windows Server 2016 以降でのみサポートされ、古い OS では空欄になることがあります。混在環境では PrincipalSource だけに依存せず、対象名や SID も合わせて確認したほうが安全です。(Microsoft Learn)
どうしても LocalAccounts モジュールを使えない古い環境では、Windows 組み込みの net localgroup が代替になります。ローカルグループの追加・表示・変更に対応しますが、新規の自動化では PowerShell の LocalAccounts コマンドレットのほうが確認処理や -WhatIf を組み込みやすく、保守しやすいです。(Microsoft Learn)
PowerShellでローカル管理者追加を行う最小コード
まずは、既存のドメイングループをローカル Administrators に追加する最小形から始めるのが分かりやすいです。最初の実行は必ず -WhatIf を付けて、対象名と追加先が想定どおりかを確認します。
$Member = 'CONTOSO\Helpdesk-LocalAdmins'
$AdministratorsSid = 'S-1-5-32-544'
$alreadyMember = Get-LocalGroupMember -SID $AdministratorsSid -Member $Member -ErrorAction SilentlyContinue
if (-not $alreadyMember) {
Add-LocalGroupMember -SID $AdministratorsSid -Member $Member -WhatIf
# 問題なければ -WhatIf を外して再実行
}
Get-LocalGroupMember -SID $AdministratorsSid |
Select-Object Name, ObjectClass, PrincipalSource
この形なら、追加前確認、試行実行、追加後確認の3つを最小コストで入れられます。Get-LocalGroupMember はグループを SID で指定でき、-Member は名前または SID で指定できます。Add-LocalGroupMember もグループ側を -SID で指定でき、-WhatIf をサポートしています。(Microsoft Learn)
ローカルユーザーを追加したい場合は、BreakGlassAdmin のような短い名前だけで渡さず、$env:COMPUTERNAME\BreakGlassAdmin のように明示しておくほうが後から見返しやすく、同名アカウントの取り違えも避けやすくなります。ドメイン参加端末での同名取り違え対策としても、この書き方は有効です。(Microsoft Learn)
実運用でそのまま使いやすいサンプルスクリプト
以下は、冪等化・ログ・戻しやすさを最低限押さえたサンプルです。単発の手作業より、タスクスケジューラや構成管理ツールから同じ処理を繰り返し呼ぶ場面で使いやすい形です。
function Add-SafeLocalAdministrator {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)]
[string]$Member, # 例: CONTOSO\Helpdesk-LocalAdmins / HOST01\BreakGlassAdmin
[string]$AdministratorsSid = 'S-1-5-32-544',
[string]$LogDirectory = 'C:\ProgramData\LocalAdminAutomation\Logs'
)
$ErrorActionPreference = 'Stop'
$null = New-Item -Path $LogDirectory -ItemType Directory -Force -ErrorAction SilentlyContinue
$LogPath = Join-Path $LogDirectory ("AddLocalAdmin_{0:yyyyMMdd_HHmmss}.txt" -f (Get-Date))
$TranscriptStarted = $false
try {
Start-Transcript -Path $LogPath -NoClobber | Out-Null
$TranscriptStarted = $true
$Group = Get-LocalGroup -SID $AdministratorsSid
$Existing = Get-LocalGroupMember -SID $AdministratorsSid -Member $Member -ErrorAction SilentlyContinue
if ($Existing) {
return [pscustomobject]@{
Result = 'Skipped'
Member = $Member
Group = $Group.Name
GroupSid = $AdministratorsSid
LogPath = $LogPath
Reason = 'AlreadyMember'
}
}
if (-not $PSCmdlet.ShouldProcess("$($Group.Name) [$AdministratorsSid]", "Add $Member")) {
return [pscustomobject]@{
Result = 'WhatIf'
Member = $Member
Group = $Group.Name
GroupSid = $AdministratorsSid
LogPath = $LogPath
Reason = 'SimulationOnly'
}
}
Add-LocalGroupMember -SID $AdministratorsSid -Member $Member -ErrorAction Stop
$Verified = Get-LocalGroupMember -SID $AdministratorsSid -Member $Member -ErrorAction SilentlyContinue
[pscustomobject]@{
Result = if ($Verified) { 'Added' } else { 'VerifyFailed' }
Member = $Member
Group = $Group.Name
GroupSid = $AdministratorsSid
LogPath = $LogPath
}
}
catch {
Write-Error $_
throw
}
finally {
if ($TranscriptStarted) {
Stop-Transcript | Out-Null
}
}
}
実行例は次の2段階に分けるのが安全です。
Add-SafeLocalAdministrator -Member 'CONTOSO\Helpdesk-LocalAdmins' -WhatIf
Add-SafeLocalAdministrator -Member 'CONTOSO\Helpdesk-LocalAdmins'
このスクリプトで押さえている要点は、追加先を SID で固定していること、既存メンバーなら Skipped を返して重複追加を避けること、-WhatIf では WhatIf を返して本番変更を止めること、Start-Transcript で実行ログを残すこと、最後に Get-LocalGroupMember で検証していることです。Start-Transcript は入力したコマンドとコンソール出力を記録でき、Add-LocalGroupMember / Get-LocalGroupMember はいずれも SID 指定をサポートします。(Microsoft Learn)
さらに厳密にしたいなら、メンバー側も名前ではなく SID で解決してから追加・削除する設計にすると、同名アカウントにさらに強くできます。Add-LocalGroupMember と Remove-LocalGroupMember は、メンバーを名前・SID・LocalPrincipal で受け取れます。(Microsoft Learn)
戻し方を先に作ってから本番に入る
ローカル管理者追加を自動化するときは、追加スクリプトだけで終わらせないことが大切です。権限付与の自動化は、緊急時の権限回収が遅いと逆に危険になります。少なくとも、事前スナップショットとRemove スクリプトは同じタイミングで用意しておくべきです。(Microsoft Learn)
$Member = 'CONTOSO\Helpdesk-LocalAdmins'
$AdministratorsSid = 'S-1-5-32-544'
Get-LocalGroupMember -SID $AdministratorsSid |
Select-Object Name, ObjectClass, PrincipalSource |
Export-Csv 'C:\ProgramData\LocalAdminAutomation\Administrators-before.csv' -NoTypeInformation -Encoding utf8
Remove-LocalGroupMember -SID $AdministratorsSid -Member $Member -WhatIf
# 問題なければ -WhatIf を外して再実行
Remove-LocalGroupMember もグループ側を -SID で指定でき、-Member は名前または SID で渡せます。最初は -WhatIf で確認し、削除前後のメンバー一覧を残しておくと、想定外の影響範囲を追いやすくなります。(Microsoft Learn)
ローカル管理者用アカウントを作るなら、追加と同時にパスワード運用も設計する
やむを得ずローカル管理者用のアカウントを新規作成する場合は、New-LocalUser -Password で作成し、必要なら Set-LocalUser で後からパスワードを更新できます。ただし、アカウントを作って Administrators に追加しただけでは運用は終わりません。ローカル管理者アカウントのパスワードは、Windows LAPS のような仕組みで別管理にする前提で考えたほうが安全です。Windows LAPS はローカル管理者アカウントのパスワードを自動管理・バックアップでき、Intune ではパスワード要件やローテーションも管理できます。(Microsoft Learn)
$Password = Read-Host 'BreakGlassAdmin のパスワード' -AsSecureString
New-LocalUser `
-Name 'BreakGlassAdmin' `
-Password $Password `
-Description 'Emergency local admin managed by IT'
Add-SafeLocalAdministrator -Member "$env:COMPUTERNAME\BreakGlassAdmin"
特に見落としやすいのは、LAPS は「ローカル管理者のパスワード管理」の仕組みであって、Administrators グループのメンバー管理そのものではないという点です。Intune の Windows LAPS は 1 台につき 1 つのローカル管理者アカウント管理を前提にしているため、複数の常設ローカル管理者を増やす設計とは相性がよくありません。(Microsoft Learn)
端末数が増えるなら、PowerShell単発からポリシー管理へ移す
台数が増えてきたら、PowerShell は「初期投入」「緊急修復」「一時対応」に寄せ、定常運用は GPO や Intune に移したほうがブレが減ります。設定場所を迷いやすいところだけ、先にまとめると次のとおりです。
| 方法 | 設定場所 | 向いている環境 |
|---|---|---|
| GPO Preferences | Computer Configuration > Preferences > Control Panel Settings > Local Users and Groups | AD参加PC |
| Intune | Endpoint Security > Account protection > Create Policy > Windows > Local user group membership | Intune / Microsoft Entra 管理PC |
| MDM CSP | ./Device/Vendor/MSFT/Policy/Config/LocalUsersAndGroups/Configure | カスタムMDM・CSP設計 |
| LAPS | GPOなら Computer Configuration > Administrative Templates > System > LAPS | ローカル管理者のパスワード管理 |
設定場所と役割の根拠は、Group Policy Preferences の Local Users and Groups 拡張、Intune の Account protection / Local user group membership、MDM の LocalUsersAndGroups CSP、Windows LAPS の公式ドキュメントです。(Microsoft Learn)
AD 管理なら GPO Preferences が扱いやすい
GPO Preferences の Local Users and Groups では、ローカルグループの作成・更新・削除に加えて、メンバーの追加や削除も中央から扱えます。Active Directory 配下の端末に「このドメイングループをローカル Administrators に入れる」という配布を標準化したいなら、PowerShell を各端末で個別実行するより管理しやすい選択肢です。(Microsoft Learn)
ただし GPO Preferences は、通常の「強制ポリシー」とは性格が違います。ユーザーや設定側の変更が一定期間残り、次回の Group Policy 更新時に再適用される振る舞いです。端末上での一時的なズレを完全に許さない設計にしたいなら、この違いを理解して使う必要があります。(Microsoft Learn)
Intune 管理なら Local user group membership が第一候補
Intune の Account protection には Local user group membership プロファイルがあり、Windows 10 20H2 以降と Windows 11 で、built-in local groups のメンバーを add / remove / replace できます。クラウド管理 PC やハイブリッド環境で、ローカル管理者追加を PowerShell スクリプト配布ではなくポリシー管理に寄せたいなら、かなり扱いやすい方法です。(Microsoft Learn)
Restricted Groups は「差分追加」ではなく「全置換」と理解する
Restricted Groups 系の設定を軽い気持ちで使うと、今いるメンバーのうち、ポリシーに書いていないものを外してしまいます。LocalUsersAndGroups CSP でも Replace は同じ考え方で、未指定メンバーが削除されます。Microsoft は Windows 10 20H2 以降では RestrictedGroups より LocalUsersAndGroups の利用を推奨しており、両方を同じ端末に適用することも未サポートです。(Microsoft Learn)
「この1グループだけ追加したい」のであれば、Restricted Groups ではなく、差分追加ができる Update 系の仕組みを選ぶほうが安全です。既存メンバーを意図せず落とす事故は、ローカル管理者追加の自動化で最も避けたい失敗の一つです。(Microsoft Learn)
常設のローカル管理者を減らしたいなら JEA を検討する
要件が「OS 全体の管理者権限を配ること」ではなく、「特定の PowerShell 操作だけ任せたいこと」なら、JEA のほうが筋が良いことがあります。JEA は delegated administration のための技術で、実行できる cmdlet や関数を制限でき、Transcript とログで何を実行したかも追跡できます。常設の管理者を減らしたい運用には相性がよいです。(Microsoft Learn)
迷ったときの選び方
- 1台または少数端末にすぐ対応したいなら、
Add-LocalGroupMemberを SID 指定で包んだ冪等スクリプトを使い、-WhatIfと Transcript をセットにするのが最短です。(Microsoft Learn) - Active Directory 配下の端末へ継続的に配るなら、GPO Preferences の Local Users and Groups で管理したほうが、スクリプトばらまきより一貫性を保ちやすいです。(Microsoft Learn)
- Intune / Microsoft Entra 管理 PC なら、Account protection の
Local user group membershipを第一候補にすると、add / remove / replace をポリシーで統制できます。(Microsoft Learn) - ローカル管理者アカウントを残すなら、メンバー追加とは別に Windows LAPS でパスワード管理を行うべきです。(Microsoft Learn)
- 「特定の管理作業だけ許可したい」なら、Administrators 追加ではなく JEA を検討したほうが、権限の出し過ぎを防ぎやすいです。(Microsoft Learn)
まとめ
PowerShellでローカル管理者追加を安全に自動化するなら、答えは単純です。Add-LocalGroupMember を使う前に、Administrators を SID S-1-5-32-544 で特定し、対象名を完全修飾で渡し、追加前確認・-WhatIf・ログ・削除手順を一緒に作ることです。台数が増えるなら GPO または Intune に寄せ、ローカル管理者アカウントを残すなら LAPS、常設権限を減らしたいなら JEA を組み合わせてください。(Microsoft Learn)
今日やるべき作業は3つです。まず、現在ローカル管理者に入っている個人アカウントを洗い出す。次に、追加対象を個人ではなく管理用グループへ寄せる。最後に、本番投入前の -WhatIf 実行と Remove-LocalGroupMember の戻し手順をセットで用意する。ここまでやれば、PowerShell でのローカル管理者追加は「危ない手作業」から「監査できる運用」に変えられます。(Microsoft Learn)

コメント