PowerShell 技能连载 - 组策略自动化管理

适用于 PowerShell 5.1 及以上版本,需要 GroupPolicy 模块

组策略(Group Policy)是 Windows 域环境中管理配置和安全设置的核心机制。通过 GPO,管理员可以集中控制数千台计算机的注册表设置、安全策略、软件部署和脚本执行。在大型企业环境中,GPO 数量往往达到数百甚至上千个,涵盖安全基线、合规要求、桌面标准化等多个维度。

手动管理这些 GPO 不仅耗时,而且极易出错——一个配置遗漏可能导致全公司的安全防线出现缺口。传统的图形界面操作(GPMC)在面对批量创建、迁移、审计等场景时显得力不从心,尤其当组织需要在不同域或林之间迁移策略时,手动操作几乎不可行。

PowerShell 的 GroupPolicy 模块提供了完整的 GPO 生命周期管理能力,从创建、编辑、备份、还原到合规报告,全部可以通过脚本自动化完成。结合 ActiveDirectory 模块,还能实现基于组织单元(OU)结构的智能策略分配和变更追踪,让组策略管理变得可重复、可审计、可回溯。

GPO 基础管理

以下脚本展示了 GPO 的创建、链接、备份和还原等基础操作,这些是日常管理中最常用的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 导入 GroupPolicy 模块
Import-Module GroupPolicy

# 定义常用变量
$Domain = "contoso.com"
$BackupPath = "C:\GPOBackup\$(Get-Date -Format 'yyyyMMdd')"

# 创建新的 GPO
$GPO = New-GPO -Name "Security Baseline 2026" -Comment "年度安全基线策略"

# 将 GPO 链接到指定的 OU,并设置优先级
New-GPLink -Name "Security Baseline 2026" -Target "OU=Servers,DC=contoso,DC=com" -LinkEnabled Yes -Order 1

# 禁用 GPO 的用户配置部分(仅保留计算机配置)
$GPO | Set-GPO -GpoStatus UserSettingsDisabled

# 创建备份目录并备份所有 GPO
if (-not (Test-Path $BackupPath)) {
New-Item -Path $BackupPath -ItemType Directory -Force | Out-Null
}

$BackupReport = Backup-GPO -All -Path $BackupPath
$BackupReport | Select-Object DisplayName, GpoId, BackupId, Timestamp |
Format-Table -AutoSize

# 导出备份清单为 CSV,便于后续还原时查找
$BackupReport | Export-Csv -Path "$BackupPath\BackupInventory.csv" -NoTypeInformation -Encoding UTF8

# 从备份还原单个 GPO(模拟灾难恢复场景)
$LatestBackup = $BackupReport | Where-Object { $_.DisplayName -eq "Security Baseline 2026" }
Restore-GPO -Name "Security Baseline 2026" -Path $BackupPath -BackupId $LatestBackup.BackupId

# 查看域中所有 GPO 的概览
Get-GPO -All | Select-Object DisplayName, GpoStatus, CreationTime, ModificationTime |
Sort-Object ModificationTime -Descending |
Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
DisplayName           GpoId                                 BackupId                             Timestamp
------------ ----- -------- ---------
Security Baseline 2026 3a1b2c4d-5e6f-... a7b8c9d0-e1f2-... 2026/2/24 10:30:15
Domain Controllers f3e2d1c0-b9a8-... 1a2b3c4d-5e6f-... 2026/2/20 14:22:10
Default Domain Policy 7f8e9d0a-1b2c-... 3c4d5e6f-7a8b-... 2026/1/15 09:12:00

DisplayName GpoStatus CreationTime ModificationTime
------------ --------- ------------ ----------------
Security Baseline 2026 UserSettingsDisabled 2026/2/24 10:30:00 2026/2/24 10:32:00
Default Domain Policy AllSettingsEnabled 2024/3/1 08:00:00 2026/1/15 09:12:00
Domain Controllers AllSettingsEnabled 2024/3/1 08:00:00 2026/2/20 14:22:10

策略设置编辑

创建 GPO 只是第一步,实际管理工作中有大量策略项需要配置。以下脚本演示了如何通过注册表首选项、安全设置和脚本部署来编辑 GPO 内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# --- 注册表首选项:通过 GPO 推送注册表项 ---
$GPOName = "Security Baseline 2026"
$Domain = "contoso.com"

# 设置注册表项:禁用 SMBv1(安全加固)
Set-GPPrefRegistryValue -Name $GPOName -Context Computer -Action Create `
-Key "SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" `
-ValueName "SMB1" -Value 0 -Type DWord -Order 1

# 设置注册表项:启用 PowerShell 脚本块日志记录
Set-GPPrefRegistryValue -Name $GPOName -Context Computer -Action Create `
-Key "SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" `
-ValueName "EnableScriptBlockLogging" -Value 1 -Type DWord -Order 2

# 设置注册表项:配置 Windows Defender 实时保护
Set-GPPrefRegistryValue -Name $GPOName -Context Computer -Action Create `
-Key "SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection" `
-ValueName "DisableRealtimeMonitoring" -Value 0 -Type DWord -Order 3

# --- 安全设置:通过 ini 文件方式配置账户策略 ---
# 生成安全模板 INF 文件
$SecTemplatePath = "C:\Temp\SecurityTemplate.inf"
$InfContent = @"
[Unicode]
Unicode=yes
[Version]
signature=`"`$CHICAGO`$`"
Revision=1
[Account Policies]
[Password History]
MaximumPasswordAge = 90
MinimumPasswordAge = 1
MinimumPasswordLength = 14
PasswordComplexity = 1
[Lockout]
LockoutDuration = 30
LockoutBadCount = 5
ResetLockoutCount = 30
"@

Set-Content -Path $SecTemplatePath -Value $InfContent -Encoding Unicode

# --- 脚本部署:配置启动脚本 ---
$ScriptName = "Install-EndpointAgent.ps1"
$ScriptContent = @'
# 端点代理安装脚本 - 由组策略推送执行
$AgentPath = "\\contoso.com\SYSVOL\contoso.com\scripts\EndpointAgent.msi"
$LogPath = "C:\Logs\AgentInstall.log"

if (-not (Get-Service -Name "EndpointAgent" -ErrorAction SilentlyContinue)) {
Start-Process msiexec.exe -ArgumentList "/i `"$AgentPath`" /qn /l*v `"$LogPath`"" -Wait
Write-Output "$(Get-Date) - Endpoint Agent installed successfully" | Out-File $LogPath -Append
}
'@

# 将脚本保存到 GPO 的启动脚本目录
$GPO = Get-GPO -Name $GPOName
$StartupScriptFolder = "\\$Domain\SYSVOL\$Domain\Policies\{$($GPO.Id)}\Machine\Scripts\Startup"
if (-not (Test-Path $StartupScriptFolder)) {
New-Item -Path $StartupScriptFolder -ItemType Directory -Force | Out-Null
}
Set-Content -Path "$StartupScriptFolder\$ScriptName" -Value $ScriptContent -Encoding UTF8

Write-Host "策略设置编辑完成:注册表首选项 3 项、安全模板 1 份、启动脚本 1 个"

执行结果示例:

1
策略设置编辑完成:注册表首选项 3 项、安全模板 1 份、启动脚本 1 

合规审计与报告

策略配置完成后,持续的合规审计至关重要。以下脚本实现了 RSOP(策略结果集)分析、基线对比和变更追踪功能,帮助管理员及时发现策略漂移。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# --- RSOP 分析:获取目标计算机的实际策略应用结果 ---
$ComputerName = "SRV-DC01.contoso.com"

# 生成 GPO 报告(HTML 格式)
$ReportPath = "C:\Reports\GPOReport_$(Get-Date -Format 'yyyyMMdd_HHmmss').html"
Get-GPOReport -All -ReportType Html -Path $ReportPath
Write-Host "GPO 报告已生成: $ReportPath"

# 获取指定计算机的 RSOP 报告
$RsopReport = "C:\Reports\RSOP_$ComputerName`_$(Get-Date -Format 'yyyyMMdd').html"
gpresult /s $ComputerName /h $RsopReport /f 2>$null
Write-Host "RSOP 报告已生成: $RsopReport"

# --- 基线对比:检测 GPO 是否偏离已知良好配置 ---
$BaselinePath = "C:\GPOBaseline"
$CurrentBackupPath = "C:\GPOBackup\$(Get-Date -Format 'yyyyMMdd')"

# 比较基线和当前备份中的 GPO 数量
$BaselineGPOs = Get-ChildItem -Path $BaselinePath -Directory
$CurrentGPOs = Get-ChildItem -Path $CurrentBackupPath -Directory

$Missing = $BaselineGPOs.Name | Where-Object { $_ -notin $CurrentGPOs.Name }
$New = $CurrentGPOs.Name | Where-Object { $_ -notin $BaselineGPOs.Name }

if ($Missing) {
Write-Warning "以下基线 GPO 在当前备份中缺失: $($Missing -join ', ')"
}
if ($New) {
Write-Host "发现新增 GPO: $($New -join ', ')" -ForegroundColor Yellow
}

# --- 变更追踪:监控 GPO 的修改时间和设置变更 ---
$AuditLog = "C:\Reports\GPO_AuditLog_$(Get-Date -Format 'yyyyMMdd').csv"

# 获取所有 GPO 的当前状态快照
$Snapshot = Get-GPO -All | ForEach-Object {
$Links = (Get-GPOReport -Name $_.DisplayName -ReportType Xml)
$LinkCount = ([xml]$Links).GPO.LinksTo | Measure-Object | Select-Object -ExpandProperty Count

[PSCustomObject]@{
GPOName = $_.DisplayName
GpoId = $_.Id
Status = $_.GpoStatus
LinkCount = $LinkCount
ComputerEnabled = ($_.GpoStatus -ne 'ComputerSettingsDisabled' -and $_.GpoStatus -ne 'AllSettingsDisabled')
UserEnabled = ($_.GpoStatus -ne 'UserSettingsDisabled' -and $_.GpoStatus -ne 'AllSettingsDisabled')
ModifiedTime = $_.ModificationTime
AuditTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
}
}

$Snapshot | Export-Csv -Path $AuditLog -NoTypeInformation -Encoding UTF8

# 标记最近 7 天内修改过的 GPO
$RecentChanges = $Snapshot | Where-Object { $_.ModifiedTime -gt (Get-Date).AddDays(-7) }
if ($RecentChanges) {
Write-Host "`n最近 7 天内修改的 GPO:" -ForegroundColor Cyan
$RecentChanges | Format-Table GPOName, ModifiedTime, LinkCount, Status -AutoSize
} else {
Write-Host "`n最近 7 天内无 GPO 变更" -ForegroundColor Green
}

Write-Host "`n审计快照已保存: $AuditLog"

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
GPO 报告已生成: C:\Reports\GPOReport_20260224_103500.html
RSOP 报告已生成: C:\Reports\RSOP_SRV-DC01.contoso.com_20260224.html
发现新增 GPO: Security Baseline 2026

最近 7 天内修改的 GPO:

GPOName ModifiedTime LinkCount Status
------- ------------- --------- ------
Security Baseline 2026 2026/2/24 10:32:00 1 UserSettingsDisabled
Domain Controllers 2026/2/20 14:22:10 1 AllSettingsEnabled

审计快照已保存: C:\Reports\GPO_AuditLog_20260224.csv

注意事项

  1. 权限要求:管理 GPO 需要域管理员或 Group Policy Creator Owners 组的成员权限。在生产环境中建议使用最小特权原则,为 GPO 管理员分配专门的委派权限,而非直接使用 Domain Admins 账户。

  2. 备份策略:建议建立定期自动备份机制,每次变更 GPO 前都执行 Backup-GPO。备份文件应存储在独立的文件服务器上,并纳入常规数据保护方案。备份 ID(BackupId)是还原时的关键标识,务必通过 CSV 清单妥善保管。

  3. 测试先行:新 GPO 或重大变更应先在测试 OU 上验证效果,确认无误后再推广到生产 OU。可以使用 New-GPLink-WhatIf 参数预览链接操作,或者先将 GPO 链接设置为禁用状态(-LinkEnabled No),验证后再启用。

  4. WMI 筛选器:复杂的策略分发场景可以结合 WMI 筛选器实现条件化应用,例如只对特定操作系统版本或硬件类型的计算机生效。但过多的 WMI 筛选器会影响组策略处理性能,建议控制在合理范围内。

  5. 脚本块日志安全:通过 GPO 启用 PowerShell 脚本块日志记录时,会产生大量日志数据。需要提前规划日志收集和存储方案(如 Windows Event Forwarding 或 SIEM 集成),避免本地日志溢出导致关键审计数据丢失。

  6. 跨域迁移:使用 Backup-GPOImport-GPO 进行跨域迁移时,需要注意安全主体(用户、组)的 SID 映射问题。迁移表格(Migration Table)是解决这一问题的关键工具,建议在迁移前使用 New-MigrationTable 生成并仔细校验映射关系。

PowerShell 技能连载 - Active Directory 用户管理

适用于 PowerShell 5.1(Windows),需要 ActiveDirectory 模块及管理员权限

Active Directory 是企业 Windows 网络的身份基础,用户账号的创建、修改、禁用、报告是系统管理员的日常任务。AD 用户管理看似简单——在图形界面里点几下鼠标就行,但当需要批量处理几十上百个账号时,手动操作既耗时又容易出错。PowerShell 的 ActiveDirectory 模块提供了完整的用户生命周期管理能力,从批量创建到权限审计,一条命令就能替代数十次点击。

本文将介绍 AD 用户管理的常用操作和批量自动化方案。

用户查询与报告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 导入模块
Import-Module ActiveDirectory

# 查询用户基本信息
Get-ADUser -Identity "zhangsan" -Properties DisplayName, Department, Title, LastLogonDate |
Select-Object SamAccountName, DisplayName, Department, Title, Enabled, LastLogonDate |
Format-List

# 搜索特定部门的用户
$users = Get-ADUser -Filter { Department -eq "工程部" -and Enabled -eq $true } `
-Properties DisplayName, EmailAddress, Title, WhenCreated

$users | Select-Object DisplayName, EmailAddress, Title, WhenCreated |
Format-Table -AutoSize

Write-Host "工程部活跃用户:$($users.Count) 人" -ForegroundColor Green

# 查找长期未登录的用户(90 天未活动)
$inactiveDate = (Get-Date).AddDays(-90)
$inactive = Get-ADUser -Filter { LastLogonDate -lt $inactiveDate -and Enabled -eq $true } `
-Properties DisplayName, LastLogonDate, Department |
Sort-Object LastLogonDate |
Select-Object DisplayName, Department, LastLogonDate

Write-Host "90 天未登录的活跃账号:$($inactive.Count) 个" -ForegroundColor Yellow
$inactive | Format-Table -AutoSize

# 即将过期的密码统计
$expiringSoon = Get-ADUser -Filter { Enabled -eq $true -and PasswordNeverExpires -eq $false } `
-Properties DisplayName, PasswordLastSet, "msDS-UserPasswordExpiryTimeComputed" |
Where-Object {
$expiry = [datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")
$expiry -lt (Get-Date).AddDays(7) -and $expiry -gt (Get-Date)
} |
Select-Object DisplayName,
@{N='PasswordExpires'; E={ [datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed") }}

Write-Host "7 天内密码过期的用户:$($expiringSoon.Count) 人" -ForegroundColor Red
$expiringSoon | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SamAccountName : zhangsan
DisplayName : 张三
Department : 工程部
Title : 高级工程师
Enabled : True
LastLogonDate : 2025/9/1 14:30:00

工程部活跃用户:15
90 天未登录的活跃账号:8
DisplayName Department LastLogonDate
----------- ---------- -------------
王五 市场部 2025/5/10
赵六 财务部 2025/4/15

7 天内密码过期的用户:3
DisplayName PasswordExpires
----------- ----------------
张三 2025/9/5
李四 2025/9/3

批量用户创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# 从 CSV 批量创建用户
$csvData = @"
Name,DisplayName,Department,Title,Manager
li.si,李四,工程部,工程师,zhangsan
wang.wu,王五,市场部,市场专员,zhangsan
zhao.liu,赵六,财务部,会计,lisi
chen.qi,陈七,工程部,初级工程师,zhangsan
"@ | ConvertFrom-Csv

function New-BatchADUsers {
param(
[Parameter(Mandatory)]
[object[]]$UserData,

[string]$BaseOU = "OU=员工,DC=contoso,DC=com",

[string]$DefaultPassword = "P@ssw0rd!2025",

[string]$UPNSuffix = "contoso.com"
)

$results = @()
$successCount = 0
$failCount = 0

$securePassword = ConvertTo-SecureString $DefaultPassword -AsPlainText -Force

foreach ($user in $UserData) {
try {
# 检查是否已存在
$existing = Get-ADUser -Filter { SamAccountName -eq $user.Name } -ErrorAction SilentlyContinue
if ($existing) {
Write-Host "用户已存在:$($user.Name)" -ForegroundColor Yellow
$results += @{ Name = $user.Name; Status = "已存在" }
continue
}

# 创建用户
$newUserParams = @{
Name = $user.DisplayName
DisplayName = $user.DisplayName
SamAccountName = $user.Name
UserPrincipalName = "$($user.Name)@$UPNSuffix"
GivenName = ($user.DisplayName -split '')[1]
Surname = ($user.DisplayName -split '')[0]
Department = $user.Department
Title = $user.Title
Path = $BaseOU
AccountPassword = $securePassword
Enabled = $true
ChangePasswordAtLogon = $true
}

if ($user.Manager) {
$newUserParams['Manager'] = $user.Manager
}

New-ADUser @newUserParams
$successCount++
Write-Host "已创建:$($user.Name)($($user.Department))" -ForegroundColor Green
$results += @{ Name = $user.Name; Status = "成功" }
} catch {
$failCount++
Write-Host "创建失败:$($user.Name) - $($_.Exception.Message)" -ForegroundColor Red
$results += @{ Name = $user.Name; Status = "失败:$($_.Exception.Message)" }
}
}

Write-Host "`n汇总:成功 $successCount,失败 $failCount" -ForegroundColor Cyan
return $results
}

# 执行批量创建
New-BatchADUsers -UserData $csvData

# 从 CSV 文件导入(生产环境常用)
# $importData = Import-Csv "C:\HR\NewEmployees_202509.csv"
# New-BatchADUsers -UserData $importData

执行结果示例:

1
2
3
4
5
已创建:li.si(工程部)
已创建:wang.wu(市场部)
已创建:zhao.liu(财务部)
已创建:chen.qi(工程部)
汇总:成功 4,失败 0

用户生命周期管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 批量修改用户属性
$users = @("li.si", "wang.wu")
foreach ($name in $users) {
Set-ADUser -Identity $name -Department "研发部" -Company "Contoso Corp"
Write-Host "已更新 $name 的部门和公司信息" -ForegroundColor Green
}

# 禁用离职用户
function Disable-DepartedUsers {
param([string[]]$UserNames)

foreach ($name in $UserNames) {
try {
$user = Get-ADUser -Identity $name -Properties DisplayName
Disable-ADAccount -Identity $name

# 移动到离职 OU
Move-ADObject -Identity $user.DistinguishedName `
-TargetPath "OU=离职员工,DC=contoso,DC=com"

# 移除所有组(保留 Domain Users)
$groups = Get-ADPrincipalGroupMembership -Identity $name |
Where-Object { $_.Name -ne "Domain Users" }
foreach ($group in $groups) {
Remove-ADGroupMember -Identity $group.SamAccountName -Members $name -Confirm:$false
}

Write-Host "已禁用并归档:$($user.DisplayName)($name)" -ForegroundColor Yellow
} catch {
Write-Host "处理失败:$name - $($_.Exception.Message)" -ForegroundColor Red
}
}
}

Disable-DepartedUsers -UserNames @("zhao.liu")

# 用户组管理
function Set-UserDepartmentGroups {
param(
[string]$UserName,
[string]$Department
)

$deptGroups = @{
"工程部" = @("SG_Developers", "SG_Git_Access", "SG_Build_Servers")
"市场部" = @("SG_Marketing", "SG_CRM_Access")
"财务部" = @("SG_Finance", "SG_ERP_Access", "SG_Reporting")
}

$groups = $deptGroups[$Department]
if (-not $groups) {
Write-Host "未定义 $Department 的默认组" -ForegroundColor Yellow
return
}

foreach ($group in $groups) {
try {
Add-ADGroupMember -Identity $group -Members $UserName -ErrorAction Stop
Write-Host "已加入组:$group" -ForegroundColor Green
} catch {
Write-Host "加入组失败:$group - $($_.Exception.Message)" -ForegroundColor Red
}
}
}

Set-UserDepartmentGroups -UserName "chen.qi" -Department "工程部"

执行结果示例:

1
2
3
4
5
6
已更新 li.si 的部门和公司信息
已更新 wang.wu 的部门和公司信息
已禁用并归档:赵六(zhao.liu)
已加入组:SG_Developers
已加入组:SG_Git_Access
已加入组:SG_Build_Servers

注意事项

  1. 权限要求:AD 操作需要相应权限,建议使用最小权限原则,为管理账号分配专门的 OU 管理权限
  2. 密码策略:批量创建用户时设置的初始密码应符合域密码策略要求
  3. 测试先行:批量操作前先用 -WhatIf 参数预览变更,确认无误后再执行
  4. 日志审计:AD 关键操作应记录日志,包括操作人、时间、变更内容
  5. OU 结构:用户创建前确认目标 OU 路径正确,避免创建到错误位置
  6. 同步延迟:多域控制器环境下,修改后存在复制延迟,不要立即在另一台 DC 上查询验证

PowerShell 技能连载 - Active Directory 管理

适用于 Windows Server 2012 R2 及以上版本,需安装 ActiveDirectory 模块

Active Directory(AD)是企业 IT 基础设施的核心——用户、计算机、组策略、DNS 都围绕 AD 展开。传统上管理员依赖 Active Directory Users and Computers(ADUC)图形界面操作,但面对成百上千的用户账户和组管理需求时,GUI 操作效率极低。PowerShell 的 ActiveDirectory 模块提供了完整的 AD 管理能力,可以实现批量创建、查询、修改和审计。

本文将讲解 AD 用户管理、组管理、计算机管理和常见自动化场景。

环境准备

使用 AD 相关命令前,需要安装并导入模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 安装 AD PowerShell 模块(Windows Server)
Install-WindowsFeature -Name RSAT-AD-PowerShell

# Windows 10/11 客户端安装 RSAT
# 设置 > 应用 > 可选功能 > 添加 RSAT: Active Directory Domain Services 工具

# 导入模块
Import-Module ActiveDirectory

# 验证模块已加载
Get-Command -Module ActiveDirectory |
Select-Object Name, CommandType |
Sort-Object Name |
Select-Object -First 20 |
Format-Table -AutoSize

# 测试域连接
Get-ADDomain | Select-Object Name, DNSRoot, Forest, DomainMode |
Format-List

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Name                    CommandType
---- -----------
Get-ADComputer Function
Get-ADDomain Function
Get-ADGroup Function
Get-ADGroupMember Function
Get-ADUser Function
New-ADUser Function
Remove-ADUser Function
Set-ADUser Function

Name : contoso
DNSRoot : contoso.com
Forest : contoso.com
DomainMode : Windows2016Domain

用户管理

用户管理是 AD 运维中最频繁的操作,包括创建、查询、修改和批量操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 查询用户信息
Get-ADUser -Identity "john.doe" -Properties * |
Select-Object Name, SamAccountName, EmailAddress, Department,
Title, Manager, Enabled, LastLogonDate, PasswordLastSet |
Format-List

# 搜索用户(模糊匹配)
Get-ADUser -Filter "Name -like '*Smith*'" |
Select-Object Name, SamAccountName, Department |
Format-Table -AutoSize

# 创建新用户
$newUserParams = @{
Name = "张伟"
GivenName = "伟"
Surname = "张"
SamAccountName = "wei.zhang"
UserPrincipalName = "wei.zhang@contoso.com"
EmailAddress = "wei.zhang@contoso.com"
Department = "IT"
Title = "高级运维工程师"
Path = "OU=IT,OU=Users,DC=contoso,DC=com"
AccountPassword = (Read-Host "设置密码" -AsSecureString)
Enabled = $true
ChangePasswordAtLogon = $true
}
New-ADUser @newUserParams
Write-Host "用户已创建:wei.zhang" -ForegroundColor Green

# 修改用户属性
Set-ADUser -Identity "wei.zhang" -Department "DevOps" -Title "DevOps 工程师"

# 禁用/启用账户
Disable-ADAccount -Identity "wei.zhang"
Enable-ADAccount -Identity "wei.zhang"

# 解锁账户(用户多次输错密码后被锁定)
Unlock-ADAccount -Identity "john.doe"

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Name           : John Doe
SamAccountName : john.doe
EmailAddress : john.doe@contoso.com
Department : Engineering
Title : Senior Developer
Manager : CN=Jane Smith,OU=Managers,DC=contoso,DC=com
Enabled : True
LastLogonDate : 2025-05-22 17:30:00
PasswordLastSet: 2025-04-15 09:00:00

Name SamAccountName Department
---- -------------- ----------
Alice Smith alice.smith HR
Bob Smith bob.smith Engineering

用户已创建:wei.zhang

批量用户管理

从 CSV 文件批量创建用户是最常见的自动化场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 批量创建用户(从 CSV)
$usersCsv = @"
Name,SamAccountName,Department,Title,Email
李明,ming.li,Engineering,开发工程师,ming.li@contoso.com
王芳,fang.wang,Marketing,市场经理,fang.wang@contoso.com
赵强,qiang.zhao,Finance,财务分析师,qiang.zhao@contoso.com
刘洋,yang.liu,IT,系统管理员,yang.liu@contoso.com
"@ | ConvertFrom-Csv

$password = ConvertTo-SecureString "P@ssw0rd123!" -AsPlainText -Force

$results = foreach ($user in $usersCsv) {
try {
$ouPath = "OU=$($user.Department),OU=Users,DC=contoso,DC=com"

New-ADUser -Name $user.Name `
-SamAccountName $user.SamAccountName `
-UserPrincipalName "$($user.SamAccountName)@contoso.com" `
-EmailAddress $user.Email `
-Department $user.Department `
-Title $user.Title `
-Path $ouPath `
-AccountPassword $password `
-Enabled $true `
-ChangePasswordAtLogon $true `
-ErrorAction Stop

[PSCustomObject]@{
User = $user.SamAccountName
Status = 'Created'
OU = $ouPath
}
} catch {
[PSCustomObject]@{
User = $user.SamAccountName
Status = "Failed: $($_.Exception.Message)"
OU = $ouPath
}
}
}

$results | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
User        Status  OU
---- ------ --
ming.li Created OU=Engineering,OU=Users,DC=contoso,DC=com
fang.wang Created OU=Marketing,OU=Users,DC=contoso,DC=com
qiang.zhao Created OU=Finance,OU=Users,DC=contoso,DC=com
yang.liu Created OU=IT,OU=Users,DC=contoso,DC=com

组管理

组是 AD 权限管理的基础单元:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 查询组信息
Get-ADGroup -Identity "IT-Admins" -Properties * |
Select-Object Name, GroupScope, GroupCategory, Description, Members |
Format-List

# 查看组成员
Get-ADGroupMember -Identity "IT-Admins" |
Select-Object Name, SamAccountName, ObjectClass |
Format-Table -AutoSize

# 添加用户到组
Add-ADGroupMember -Identity "IT-Admins" -Members "wei.zhang"
Write-Host "已将 wei.zhang 添加到 IT-Admins 组" -ForegroundColor Green

# 批量添加组成员
$members = @("ming.li", "yang.liu")
Add-ADGroupMember -Identity "DevOps-Team" -Members $members

# 从组中移除用户
Remove-ADGroupMember -Identity "IT-Admins" -Members "john.doe" -Confirm:$false

# 创建新组
New-ADGroup -Name "Cloud-Admins" `
-GroupScope Global `
-GroupCategory Security `
-Description "云平台管理员组" `
-Path "OU=Groups,DC=contoso,DC=com"

# 查找用户所属的所有组
Get-ADUser -Identity "wei.zhang" -Properties MemberOf |
Select-Object -ExpandProperty MemberOf |
ForEach-Object { ($_ -split ',')[0] -replace 'CN=','' } |
Sort-Object

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
Name          SamAccountName ObjectClass
---- -------------- -----------
John Doe john.doe user
Jane Smith jane.smith user
Server01$ SERVER01 computer

已将 wei.zhang 添加到 IT-Admins 组

Cloud-Admins
DevOps-Team
Domain Users
IT-Admins

计算机管理

AD 中的计算机账户管理用于跟踪和管理域中的服务器和工作站:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 查询域中所有计算机
Get-ADComputer -Filter * -Properties Name, OperatingSystem, LastLogonDate, Enabled |
Select-Object Name, OperatingSystem, LastLogonDate, Enabled |
Sort-Object Name |
Format-Table -AutoSize

# 按操作系统筛选
Get-ADComputer -Filter "OperatingSystem -like '*Server 2022*'" |
Select-Object Name, DNSHostName |
Format-Table -AutoSize

# 查找不活跃的计算机(90 天未登录)
$cutoffDate = (Get-Date).AddDays(-90)
$inactiveComputers = Get-ADComputer -Filter { LastLogonDate -lt $cutoffDate } `
-Properties Name, LastLogonDate, OperatingSystem

$inactiveComputers |
Select-Object Name, OperatingSystem,
@{N='LastLogon'; E={$_.LastLogonDate.ToString('yyyy-MM-dd')}} |
Format-Table -AutoSize

Write-Host "不活跃计算机数量:$($inactiveComputers.Count)" -ForegroundColor Yellow

# 禁用不活跃的计算机账户
foreach ($comp in $inactiveComputers) {
Set-ADComputer -Identity $comp -Enabled $false
Write-Host "已禁用:$($comp.Name)" -ForegroundColor Yellow
}

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Name       OperatingSystem                  LastLogonDate      Enabled
---- --------------- ------------- -------
DC01 Windows Server 2022 Standard 2025-05-23 True
SRV-WEB01 Windows Server 2022 Datacenter 2025-05-22 True
WS-HR01 Windows 11 Enterprise 2025-05-20 True
OLD-SRV01 Windows Server 2016 Standard 2025-02-15 True

Name OperatingSystem LastLogon Enabled
---- --------------- --------- -------
OLD-SRV01 Windows Server 2016 Standard 2025-02-15 True
OLD-WS01 Windows 10 Enterprise 2025-01-20 True

不活跃计算机数量:2
已禁用:OLD-SRV01
已禁用:OLD-WS01

密码策略与合规检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 查看域密码策略
Get-ADDefaultDomainPasswordPolicy |
Select-Object ComplexityEnabled, MinPasswordLength,
MaxPasswordAge, PasswordHistoryCount, LockoutThreshold |
Format-List

# 查找密码即将过期的用户
$maxAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
$notifyDays = 14
$cutoffDate = (Get-Date).AddDays($notifyDays)

$expiringUsers = Get-ADUser -Filter { Enabled -eq $true -and PasswordNeverExpires -eq $false } `
-Properties Name, EmailAddress, PasswordLastSet, PasswordNeverExpires

$results = foreach ($user in $expiringUsers) {
$expiryDate = $user.PasswordLastSet.AddDays($maxAge)
if ($expiryDate -le $cutoffDate) {
$daysLeft = [math]::Floor(($expiryDate - (Get-Date)).TotalDays)
[PSCustomObject]@{
Name = $user.Name
Email = $user.EmailAddress
ExpiresOn = $expiryDate.ToString('yyyy-MM-dd')
DaysLeft = $daysLeft
}
}
}

$results | Sort-Object DaysLeft | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
ComplexityEnabled  : True
MinPasswordLength : 8
MaxPasswordAge : 90.00:00:00
PasswordHistoryCount : 24
LockoutThreshold : 5

Name Email ExpiresOn DaysLeft
---- ----- --------- --------
John Doe john.doe@contoso.com 2025-05-28 5
Alice Smith alice.smith@contoso.com 2025-06-01 9
Bob Smith bob.smith@contoso.com 2025-06-05 13

注意事项

  1. 权限要求:AD 操作需要足够的权限。普通用户只能查询和修改自己的部分属性,管理操作需要 AD 管理员或委派权限
  2. **批量操作加 -WhatIf**:大批量修改前始终使用 -WhatIf 参数预览操作,确认无误后再执行
  3. OU 路径正确性-Path 参数必须使用完整的 DN(Distinguished Name)格式,如 OU=IT,DC=contoso,DC=com
  4. 密码策略合规:创建用户时设置的密码必须符合域密码策略(复杂度、最小长度等),否则创建会失败
  5. 管道效率:使用 -Filter 参数在服务端过滤比管道 Where-Object 高效得多
  6. 回收站:删除用户前建议启用 AD 回收站功能,以便误删时恢复