适用于 PowerShell 5.1(Windows),需要 DnsServer 模块及管理员权限
在企业网络管理中,DNS 记录的维护是一项高频且容易出错的工作。当服务器迁移、应用上线或域名变更时,运维人员需要快速准确地添加、修改或删除 DNS 记录。手动操作 DNS 管理控制台不仅效率低下,还容易因为误操作导致服务中断。
Windows Server 自带的 DnsServer 模块提供了一整套 PowerShell cmdlet,能够以脚本化的方式管理 DNS 区域中的各类记录。结合 PowerShell 的管道和循环能力,我们可以实现批量操作、配置审计和自动化巡检,大幅提升运维效率和准确性。
本文将介绍如何使用 DnsServer 模块完成 DNS 记录的查询、创建、修改和删除操作,并提供批量管理的实用脚本模板。
查询 DNS 记录 查询是最基础的操作。使用 Get-DnsServerResourceRecord 可以列出指定区域中的所有记录,也可以按名称和类型精确筛选。下面演示了几种常见的查询方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Import-Module DnsServerGet-DnsServerResourceRecord -ZoneName "contoso.com" -RRType A | Select-Object -First 10 Get-DnsServerResourceRecord -ZoneName "contoso.com" -Name "webapp01" Get-DnsServerResourceRecord -ZoneName "contoso.com" | Where-Object { $_ .HostName -like "*test*" } | Format-Table HostName, RecordType, RecordData -AutoSize
执行结果示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 HostName RecordType Timestamp RecordData -------- ---------- --------- ---------- webapp01 A 2025/9/10 上午 10 :30 10.0.1.100 dbserver A 2025/9/8 上午 9 :15 10.0.2.50 mail A 2025/9/1 下午 3 :00 10.0.3.10 HostName RecordType Timestamp RecordData -------- ---------- --------- ---------- webapp01 A 2025/9/10 上午 10 :30 10.0.1.100 HostName RecordType Timestamp RecordData -------- ---------- --------- ---------- test-api A 2025/9/9 上午 11 :20 10.0.5.80 test-web A 2025/9/7 下午 2 :45 10.0.5.81 test-db CNAME 2025/9/5 上午 8 :00 dbserver.contoso.com.
创建 DNS 记录 使用 Add-DnsServerResourceRecord 系列 cmdlet 可以创建不同类型的 DNS 记录。常用的包括 A 记录、CNAME 记录、MX 记录和 TXT 记录。创建时需要指定区域名称、记录名称和对应的值。
下面展示如何创建几种常见的 DNS 记录类型。
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 Add-DnsServerResourceRecordA -ZoneName "contoso.com" ` -Name "webapp02" ` -IPv4Address "10.0.1.200" ` -TimeToLive 01 :00 :00 Add-DnsServerResourceRecordCName -ZoneName "contoso.com" ` -Name "www" ` -HostNameAlias "webapp01.contoso.com" ` -TimeToLive 01 :00 :00 Add-DnsServerResourceRecordMX -ZoneName "contoso.com" ` -Name "." ` -MailExchange "mail.contoso.com" ` -Preference 10 ` -TimeToLive 01 :00 :00 Add-DnsServerResourceRecordTxt -ZoneName "contoso.com" ` -Name "@" ` -DescriptiveText "v=spf1 ip4:10.0.0.0/8 -all" ` -TimeToLive 01 :00 :00 Get-DnsServerResourceRecord -ZoneName "contoso.com" -Name "webapp02"
执行结果示例:
1 2 3 -------- ---------- --------- ---------- . . .
批量导入 DNS 记录 在实际运维场景中,经常需要根据 CSV 文件批量导入 DNS 记录,例如新机房上线或大批量服务迁移。以下脚本从一个结构化的 CSV 文件中读取记录信息,逐条创建对应的 DNS 记录,并在完成后输出操作摘要。
首先准备 CSV 文件 dns-records.csv,格式如下:
1 2 3 4 Name ,Type,Value,TTLapp -server01,A,10.0.10.50 ,3600 app -server02,A,10.0.10.51 ,3600 api -gateway,CNAME,app-server01.contoso.com,3600
然后运行批量导入脚本:
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 $zoneName = "contoso.com" $csvPath = "C:\Scripts\dns-records.csv" $records = Import-Csv -Path $csvPath $successCount = 0 $failCount = 0 $results = @ ()foreach ($record in $records ) { $ttl = New-TimeSpan -Seconds $record .TTL try { switch ($record .Type) { "A" { Add-DnsServerResourceRecordA -ZoneName $zoneName ` -Name $record .Name ` -IPv4Address $record .Value ` -TimeToLive $ttl ` -ErrorAction Stop } "CNAME" { Add-DnsServerResourceRecordCName -ZoneName $zoneName ` -Name $record .Name ` -HostNameAlias $record .Value ` -TimeToLive $ttl ` -ErrorAction Stop } default { Write-Warning "不支持的记录类型: $ ($record .Type) ($ ($record .Name))" continue } } $successCount ++ $results += [PSCustomObject ]@ { Name = $record .Name Type = $record .Type Value = $record .Value Status = "成功" } Write-Host " [OK] $ ($record .Type) 记录: $ ($record .Name) -> $ ($record .Value)" -ForegroundColor Green } catch { $failCount ++ $results += [PSCustomObject ]@ { Name = $record .Name Type = $record .Type Value = $record .Value Status = "失败: $ ($_ .Exception.Message)" } Write-Host " [FAIL] $ ($record .Type) 记录: $ ($record .Name) -> $ ($_ .Exception.Message)" -ForegroundColor Red } } Write-Host "`n===== 导入摘要 =====" -ForegroundColor CyanWrite-Host "成功: $successCount 条" Write-Host "失败: $failCount 条" Write-Host "总计: $ ($records .Count) 条" $results | Format-Table -AutoSize
执行结果示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [OK] A 记录: app-server01 -> 10.0.10.50 [OK] A 记录: app-server02 -> 10.0.10.51 [OK] CNAME 记录: api-gateway -> app-server01.contoso.com ===== 导入摘要 ===== 成功: 3 条 失败: 0 条 总计: 3 条 Name Type Value Status ---- ---- ----- ------app-server01 A 10.0.10.50 成功 app-server02 A 10.0.10.51 成功 api-gateway CNAME app-server01.contoso.com 成功
修改和删除 DNS 记录 DNS 记录的修改需要先获取旧记录的引用,然后用新值创建一条记录覆盖旧记录。删除操作则相对简单,直接指定名称和类型即可。以下脚本演示了如何安全地更新 IP 地址并清理过期记录。
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 $zoneName = "contoso.com" $oldRecord = Get-DnsServerResourceRecord -ZoneName $zoneName ` -Name "webapp01" -RRType A | Select-Object -First 1 $newRecord = $oldRecord .Clone()$newRecord .RecordData.IPv4Address = [System.Net.IPAddress ]::Parse("10.0.1.150" )Set-DnsServerResourceRecord -ZoneName $zoneName ` -OldInputObject $oldRecord ` -NewInputObject $newRecord Write-Host "已将 webapp01 的 IP 从 $ ($oldRecord .RecordData.IPv4Address) 更新为 $ ($newRecord .RecordData.IPv4Address)" Remove-DnsServerResourceRecord -ZoneName $zoneName ` -Name "webapp02" ` -RRType A ` -Force ` -Confirm :$false Write-Host "已删除 webapp02 的 A 记录" Get-DnsServerResourceRecord -ZoneName $zoneName -Name "webapp01"
执行结果示例:
1 2 3 4 5 6 已将 webapp01 的 IP 从 10.0.1.100 更新为 10.0.1.150 已删除 webapp02 的 A 记录 HostName RecordType Timestamp RecordData -------- ---------- --------- ---------- webapp01 A 2025/9/12 上午 8 :10 10.0.1.150
DNS 记录审计报告 定期审计 DNS 记录有助于发现残留的过期记录、重复指向和异常配置。以下脚本生成一份简洁的审计报告,包含各类型记录的统计信息和即将过期的静态记录。
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 $zoneName = "contoso.com" $allRecords = Get-DnsServerResourceRecord -ZoneName $zoneName $summary = $allRecords | Group-Object RecordType | Sort-Object Count -Descending Write-Host "===== DNS 区域审计报告: $zoneName =====" -ForegroundColor CyanWrite-Host "生成时间: $ (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`n" foreach ($group in $summary ) { $pct = [math ]::Round(($group .Count / $allRecords .Count) * 100 , 1 ) Write-Host ("{0,-10} {1,5} 条 ({2,5}%)" -f $group .Name, $group .Count, $pct ) } Write-Host "`n总计: $ ($allRecords .Count) 条记录" $cutoff = (Get-Date ).AddDays(-30 )$staleRecords = $allRecords | Where-Object { $_ .RecordType -eq "A" -and $_ .Timestamp -lt $cutoff -and $_ .Timestamp -gt [datetime ]::MinValue } if ($staleRecords ) { Write-Host "`n--- 可能过期的 A 记录 (超过 30 天未更新) ---" -ForegroundColor Yellow foreach ($rec in $staleRecords ) { Write-Host (" {0,-25} -> {1,-15} (最后更新: {2})" -f ` $rec .HostName, ` $rec .RecordData.IPv4Address, ` ($rec .Timestamp.ToString("yyyy-MM-dd" ))) } Write-Host "`n共 $ ($staleRecords .Count) 条可能过期的记录,建议人工确认后清理。" } else { Write-Host "`n未发现超过 30 天未更新的动态 A 记录。" -ForegroundColor Green }
执行结果示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ===== DNS 区域审计报告: contoso.com ===== 生成时间: 2025-09-12 08:15:00 A 42 条 ( 52.5%) CNAME 18 条 ( 22.5%) MX 3 条 ( 3.8%) TXT 12 条 ( 15.0%) SRV 5 条 ( 6.3%) 总计: 80 条记录 --- 可能过期的 A 记录 (超过 30 天未更新) --- legacy-app -> 10.0.99.10 (最后更新: 2025-07-15) old-printer -> 10.0.99.20 (最后更新: 2025-06-28) 共 2 条可能过期的记录,建议人工确认后清理。
注意事项
管理员权限要求 :DnsServer 模块的所有写操作(添加、修改、删除)都需要以管理员身份运行 PowerShell。可以在脚本开头添加 #Requires -RunAsAdministrator 确保权限正确。
区域名称区分大小写 :虽然 DNS 协议本身不区分大小写,但在 PowerShell cmdlet 中传入区域名称时应保持与 DNS 服务器上的一致,避免因大小写差异导致查询失败。
TTL 设置要合理 :为即将变更的记录设置较短的 TTL(如 300 秒),可以缩短切换期间的 DNS 缓存影响;长期稳定的记录则可使用较长的 TTL(如 3600 秒)以减轻 DNS 服务器负载。
修改记录必须使用 Clone 方法 :Set-DnsServerResourceRecord 要求同时提供旧记录和新记录对象。务必使用 Clone() 方法创建副本再修改,直接修改原始对象会导致比较失败。
批量操作建议使用事务日志 :在批量导入或大规模变更前,先将现有记录导出为 CSV 备份。如果脚本中途出错,可以快速回滚到原始状态。
CNAME 与 A 记录的冲突 :同一个主机名不能同时存在 CNAME 记录和其他类型的记录。如果需要将 CNAME 改为 A 记录,必须先删除 CNAME 再创建 A 记录,顺序不能颠倒。