用 powershell 实现 DDNS 功能
最近想实现在外面访问家里的迷你电脑,因为电脑的 IPv6 地址是通过 SLACC 分配的,不能在路由器上获得迷你电脑的 IPv6 地址,所以需要在电脑上实现 DDNS 功能。就写了一个脚本,实现了已下功能:
- 从本地网卡获取 IPv6 的第一个首选地址,通过 cloudfalre api 获取 dns 记录的 ipv6 地址
- 对比获取的 IPv6 地址与 cloudflare 中的 dns 记录是否一致
- 如果比对失败则通过 cloudflare api 更新 dns 解析
- 发生错误则发送 telegram 通知
下面是脚本内容:
# ------------------------------------------------------------------------------
# 脚本名称: UpdateDNS.ps1
# 描述: 获取本机 IPv6 首选地址,通过 Cloudflare API 更新 DNS 记录,并发送 Telegram 通知
# 作者: [opswill]
# 日期: [2024/12/12]
# 版本: 1.0
# ------------------------------------------------------------------------------
# 注意: 请确保已正确配置 API Token 和其他变量
# ------------------------------------------------------------------------------
# 设置 PowerShell 执行策略
Set-ExecutionPolicy Bypass -Scope Process -Force
# 配置 Cloudflare API 和 Telegram Bot 信息
$apiToken = ""
$zoneId = ""
$recordId = ""
$domain = ""
$botToken = ""
$chatId = ""
# 日志文件路径
$logFilePath = "C:\DDNS.log" # 请替换为你的日志文件路径
function Log-Message {
param(
[string]$Message
)
$timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
$logEntry = "$timestamp - $Message"
Add-Content -Path $logFilePath -Value $logEntry
}
function Send-TelegramMessage {
param(
[string]$BotToken,
[string]$ChatId,
[string]$Message
)
$telegramApiUrl = "https://api.telegram.org/bot$BotToken/sendMessage"
$body = @{
chat_id = $ChatId
text = $Message
} | ConvertTo-Json -Depth 10
try {
$bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
Invoke-WebRequest -Uri $telegramApiUrl -Method POST -Body $bytes -ContentType "application/json" -UseBasicParsing | Out-Null
} catch {
Log-Message "发送Telegram通知失败,错误信息:$_"
}
}
function Get-IPv6Address {
$ipv6Address = Get-NetIPAddress -InterfaceAlias "vEthernet (vSwitch-Public-Ethernet)" |
Where-Object { $_.AddressFamily -eq "IPv6" -and $_.PrefixOrigin -eq "RouterAdvertisement" -and $_.SuffixOrigin -eq "Link" } |
Select-Object -First 1 -ExpandProperty IPAddress
if (-not $ipv6Address) {
throw "未找到有效的 IPv6 地址。"
}
return $ipv6Address
}
function Get-CurrentDNSRecord {
$uri = "https://api.cloudflare.com/client/v4/zones/$zoneId/dns_records/$recordId"
$headers = @{
"Authorization" = "Bearer $apiToken"
}
try {
$response = Invoke-WebRequest -Uri $uri -Method GET -Headers $headers -UseBasicParsing
$responseObj = $response.Content | ConvertFrom-Json
if ($responseObj.success) {
return $responseObj.result.content
} else {
throw "获取DNS记录失败,错误信息:$($responseObj.errors | ConvertTo-Json -Depth 10)"
}
} catch {
throw "获取当前DNS记录失败,错误信息:$_"
}
}
function Update-DNSRecord {
param(
[string]$ipv6Address
)
# 准备 API 请求
$uri = "https://api.cloudflare.com/client/v4/zones/$zoneId/dns_records/$recordId"
$headers = @{
"Content-Type" = "application/json"
"Authorization" = "Bearer $apiToken"
}
# 准备请求体
$body = @{
name = $domain
ttl = 60
content = $ipv6Address
type = "AAAA" # 使用 AAAA 记录类型更新 IPv6 地址
} | ConvertTo-Json -Depth 10
try {
$response = Invoke-WebRequest -Uri $uri -Method PATCH -Headers $headers -Body $body -ContentType "application/json" -UseBasicParsing
return $response
} catch {
throw "发送API请求更新DNS记录失败,错误信息:$_"
}
}
# 记录开始时间
Log-Message "脚本开始执行"
# 获取 IPv6 地址
try {
$ipv6Address = Get-IPv6Address
Log-Message "从本机网卡获取到IPv6地址: $ipv6Address"
} catch {
$message = "Windows DDNS: 获取IPv6地址失败,错误信息:$_"
Send-TelegramMessage -BotToken $botToken -ChatId $chatId -Message $message
Log-Message $message
exit
}
# 获取当前 DNS 记录
try {
$currentDNSRecord = Get-CurrentDNSRecord
Log-Message "当前 $domain 的 DNS 记录内容: $currentDNSRecord"
# 比较当前 DNS 记录与本机 IPv6 地址
if ($currentDNSRecord -ne $ipv6Address) {
Log-Message "DNS 记录与本机 IPv6 地址不一致,准备更新 DNS 记录。"
# 发送 API 请求更新 DNS 记录
$response = Update-DNSRecord -ipv6Address $ipv6Address
$responseObj = $response.Content | ConvertFrom-Json
if ($responseObj.success) {
$logMessage = "成功更新 DNS 记录: $domain -> $ipv6Address"
Log-Message $logMessage
} else {
$message = "Windows DDNS: 更新DNS记录失败,错误信息:$($responseObj.errors | ConvertTo-Json -Depth 10)"
Send-TelegramMessage -BotToken $botToken -ChatId $chatId -Message $message
Log-Message $message
}
} else {
Log-Message "DNS 记录与本机 IPv6 地址一致,无需更新。"
}
} catch {
$message = "Windows DDNS: $_"
Send-TelegramMessage -BotToken $botToken -ChatId $chatId -Message $message
Log-Message $message
}
# 记录结束时间
Log-Message "脚本执行结束"
按 win + r 然后输入 taskschd.msc 创建一个新的计划任务,从而实现开机未登录和登录状态定期执行,这样就可以通过域名在外面访问家里的迷你电脑了。