AI写的联网后自动从ntp获取当前时间,并且修改系统安装时间为当前时间
[ol]# ========== 修改当前进程执行策略 ==========
try {
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force -ErrorAction Stop
Write-Host "当前进程执行策略已临时设置为 Bypass" -ForegroundColor Green
} catch {
Write-Host "错误:无法修改当前进程的执行策略!" -ForegroundColor Red
Write-Host "原因: $($_.Exception.Message)" -ForegroundColor Red
Write-Host "请手动以管理员身份运行 PowerShell,然后执行以下命令:" -ForegroundColor Yellow
Write-Host " Set-ExecutionPolicy -Scope Process Bypass" -ForegroundColor White
Write-Host " cd `"$PSScriptRoot`""
Write-Host " .\`"$([System.IO.Path]::GetFileName($PSCommandPath))`""
Write-Host "按任意键退出..."
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit 1
}
# ========== 防火墙 NTP 端口放行(出站+入站) ==========
function Ensure-NTPFirewallRules {
Write-Host "正在配置防火墙放行所有 NTP 规则(UDP 123)..." -ForegroundColor White
$rules = @(
@{
Name = "NTP Client Outbound (UDP 123)"
Description = "允许 NTP 客户端通过 UDP 123 端口出站同步时间"
Direction = "Outbound"
LocalPort = "Any"
RemotePort = "123"
},
@{
Name = "NTP Client Inbound (UDP 123)"
Description = "允许 NTP 客户端接收 UDP 123 端口的应答数据"
Direction = "Inbound"
LocalPort = "123"
RemotePort = "Any"
}
)
$allOk = $true
foreach ($rule in $rules) {
$ruleName = $rule.Name
$existing = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
if ($existing) {
if ($existing.Enabled -eq 'True' -and $existing.Action -eq 'Allow') {
Write-Host "规则已存在并正确启用: $ruleName" -ForegroundColor Green
} else {
Write-Host "规则存在但状态异常,正在修复: $ruleName" -ForegroundColor Yellow
try {
Set-NetFirewallRule -DisplayName $ruleName -Enabled True -Action Allow -ErrorAction Stop
Write-Host "规则已修复。" -ForegroundColor Green
} catch {
Write-Host "修复失败: $($_.Exception.Message)" -ForegroundColor Red
$allOk = $false
}
}
continue
}
try {
Write-Host " → 正在创建规则: $ruleName" -ForegroundColor Yellow
New-NetFirewallRule -DisplayName $ruleName `
-Description $rule.Description `
-Direction $rule.Direction `
-Protocol UDP `
-LocalPort $rule.LocalPort `
-RemotePort $rule.RemotePort `
-Action Allow `
-Enabled True `
-Profile Any `
-ErrorAction Stop | Out-Null
Write-Host "规则已创建并启用。" -ForegroundColor Green
} catch {
Write-Host "创建失败: $($_.Exception.Message)" -ForegroundColor Red
$allOk = $false
}
}
if ($allOk) {
Write-Host "所有 NTP 防火墙规则已正确配置。" -ForegroundColor Green
} else {
Write-Host "部分规则配置失败,但仍将继续尝试同步时间。" -ForegroundColor Yellow
}
return $allOk
}
# ========== NTP 同步函数(单次请求,带重试,已修复资源泄漏) ==========
function Sync-TimeFromNTP {
param([string]$server, [int]$port = 123, [int]$retries = 3)
$attempt = 0
while ($attempt -lt $retries) {
$client = $null
try {
$ntpData = New-Object byte[] 48
$ntpData[0] = 0x1B # LI=0, VN=3, Mode=3
$client = New-Object System.Net.Sockets.UdpClient
$client.Connect($server, $port)
$null = $client.Send($ntpData, $ntpData.Length)
$client.Client.ReceiveTimeout = 5000 # 5 秒超时
$remoteEP = New-Object System.Net.IPEndPoint ([IPAddress]::Any, 0)
$receivedData = $client.Receive([ref]$remoteEP)
# 解析 Transmit Timestamp(第40-47字节)
$intPart = [UInt64]0
$fracPart = [UInt64]0
for ($i = 0; $i -lt 4; $i++) {
$intPart = ($intPart -shl 8) -bor $receivedData[40 + $i]
}
for ($i = 4; $i -lt 8; $i++) {
$fracPart = ($fracPart -shl 8) -bor $receivedData[40 + $i]
}
$ntpSeconds = [double]$intPart + ([double]$fracPart / 4294967296.0)
$unixTimestamp = $ntpSeconds - 2208988800.0
if ($unixTimestamp -le 0) {
throw "NTP 返回时间戳无效"
}
$utcTime = ([DateTime]'1970-01-01 00:00:00').AddSeconds($unixTimestamp)
return $utcTime
}
catch {
$attempt++
Write-Host " [$server] 第 $attempt 次尝试失败: $($_.Exception.Message.TrimEnd())" -ForegroundColor DarkGray
if ($attempt -lt $retries) { Start-Sleep -Milliseconds 500 }
}
finally {
if ($client) {
try { $client.Close() } catch {}
try { $client.Dispose() } catch {}
}
}
}
return $null
}
# ========== 设置系统本地时间(kernel32 调用) ==========
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class WinAPI {
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME {
public UInt16 wYear;
public UInt16 wMonth;
public UInt16 wDayOfWeek;
public UInt16 wDay;
public UInt16 wHour;
public UInt16 wMinute;
public UInt16 wSecond;
public UInt16 wMilliseconds;
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetLocalTime(ref SYSTEMTIME st);
}
"@
function Set-LocalTime {
param([DateTime]$localTime)
$st = New-Object WinAPI+SYSTEMTIME
$st.wYear = $localTime.Year
$st.wMonth = $localTime.Month
$st.wDay = $localTime.Day
$st.wDayOfWeek = [System.UInt16]$localTime.DayOfWeek
$st.wHour = $localTime.Hour
$st.wMinute = $localTime.Minute
$st.wSecond = $localTime.Second
$st.wMilliseconds = $localTime.Millisecond
return [WinAPI]::SetLocalTime([ref]$st)
}
# ========== 将 UTC DateTime 转换为 18 位 LDAP 时间戳(已修复精度问题) ==========
function ConvertTo-LDAPTimestamp {
param([DateTime]$DateTime)
$utcTime = $DateTime.ToUniversalTime()
Write-Host "计算 LDAP 时间戳基于 UTC: $($utcTime.ToString('yyyy-MM-dd HH:mm:ss'))"
$epoch = New-Object DateTime(1601, 1, 1, 0, 0, 0, [DateTimeKind]::Utc)
$ticks = $utcTime.Ticks - $epoch.Ticks
$highPart = [int64]($ticks / 10000000)
$lowPart = $ticks % 10000000
$ldapString = $highPart.ToString() + $lowPart.ToString("0000000")
return $ldapString
}
# ========== 主流程 ==========
Write-Host "`n========== 防火墙配置 ==========" -ForegroundColor Cyan
$firewallOk = Ensure-NTPFirewallRules
if (-not $firewallOk) {
Write-Host "部分防火墙规则未正确配置,但仍将继续尝试同步..." -ForegroundColor Yellow
}
$ntpServers = @(
"ntp.ntsc.ac.cn",
"time.aliyun.com",
"ntp.tencent.com",
"ntp1.aliyun.com",
"cn.pool.ntp.org",
"edu.ntp.org.cn"
)
$timeService = Get-Service -Name w32time -ErrorAction SilentlyContinue
$wasRunning = $false
if ($timeService -and $timeService.Status -eq 'Running') {
Write-Host "正在停止 w32time 服务以释放 UDP 123 端口..." -ForegroundColor Yellow
Stop-Service w32time -Force -ErrorAction SilentlyContinue
Start-Sleep -Milliseconds 500
$wasRunning = $true
}
$synced = $false
$utcResult = $null
try {
Write-Host "`n========== NTP 时间同步 ==========" -ForegroundColor Cyan
foreach ($server in $ntpServers) {
Write-Host "正在尝试从 $server 获取时间..." -ForegroundColor White
$utcResult = Sync-TimeFromNTP -server $server
if ($utcResult) {
$localTime = $utcResult.ToLocalTime()
if (Set-LocalTime -localTime $localTime) {
$synced = $true
Write-Host "时间同步成功(来源:$server)" -ForegroundColor Green
break
} else {
Write-Host "设置系统时间失败,请确认管理员权限。" -ForegroundColor Red
break
}
} else {
Write-Host "无法从 $server 获取有效时间" -ForegroundColor Yellow
}
}
}
finally {
if ($wasRunning) {
Write-Host "正在恢复 w32time 服务..." -ForegroundColor Yellow
Start-Service w32time -ErrorAction SilentlyContinue
}
}
if (-not $synced) {
Write-Host "`n所有 NTP 服务器均未能返回有效时间!" -ForegroundColor Red
Write-Host "请检查网络连接后重试。" -ForegroundColor DarkYellow
Write-Host "按任意键退出..."
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit 1
}
$utcNow = [DateTime]::UtcNow
$localNow = $utcNow.ToLocalTime()
$unixTimestamp = [int64]($utcNow - [DateTime]::new(1970,1,1,0,0,0,[DateTimeKind]::Utc)).TotalSeconds
$ntFileTime = $utcNow.ToFileTime()
Write-Host "`n同步后的时间:" -ForegroundColor Cyan
Write-Host " 本地时间 : $($localNow.ToString('yyyy-MM-dd HH:mm:ss'))"
Write-Host " Unix 时间戳 : $unixTimestamp"
Write-Host " NT 文件时间 : $ntFileTime"
$regPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
try {
if ($unixTimestamp -lt 0 -or $unixTimestamp -gt [UInt32]::MaxValue) {
throw "Unix 时间戳超出 REG_DWORD 范围"
}
New-ItemProperty -Path $regPath -Name "InstallDate" -Value ([UInt32]$unixTimestamp) -PropertyType DWord -Force | Out-Null
Write-Host "InstallDate (REG_DWORD) 写入成功" -ForegroundColor Green
$ldapTimestampString = ConvertTo-LDAPTimestamp -DateTime $utcNow
if ([string]::IsNullOrEmpty($ldapTimestampString)) {
throw "LDAP 时间戳计算结果为空"
}
$ldapTimestamp = [UInt64]$ldapTimestampString
New-ItemProperty -Path $regPath -Name "InstallTime" -Value $ldapTimestamp -PropertyType QWord -Force | Out-Null
Write-Host "InstallTime (REG_QWORD) 写入成功: $ldapTimestampString" -ForegroundColor Green
Write-Host "`n系统安装时间已成功更新!" -ForegroundColor Cyan
}
catch {
Write-Host "注册表写入失败:$($_.Exception.Message)" -ForegroundColor Red
}
Write-Host "`n按任意键退出..."
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')[/ol]复制代码
不知道为啥,直接powershell运行,临时运行策略不生效,使用Ps1_To_Exe转成exe后又没问题,用的是administrator账号测试的,求大佬指点

