修改系统安装时间

查看 161|回复 18
作者:hilltjhx   
   
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账号测试的,求大佬指点

时间, 规则, 防火墙

baby666   
还有这个操作的,试试看
baby666   
真!电脑能干的活就坚决不动手
baby666   

kedion 发表于 2026-5-7 09:50
BIOS时间不对,装出来的系统,显示的时间不正确然后被电商客户说卖二手,各种奇怪的需求都是因为被逼出来 ...

不容易啊
baby666   
感谢大神的制作,谢谢
baby666   
ai做个小玩具
挺好的
baby666   
好复杂的流程,仅采集当前系统日期就行了吧,日期不对鼠标点几下而已,NTP本身涉及的细节挺多
baby666   

baby666 发表于 2026-5-7 07:06
显得电脑是新装的吗?🤭

BIOS时间不对,装出来的系统,显示的时间不正确然后被电商客户说卖二手,各种奇怪的需求都是因为被逼出来的
baby666   

忧心的启 发表于 2026-5-7 09:01
我记得改这个就一个注册表项,用批处理一条命令就行,不用这么复杂吧?不过折腾也好,越玩越会。支持折腾起 ...

是得改两个注册表的值,而且需要转换时间戳,用ntp获取时间是因为有遇到新装的电脑,BIOS时间不对,装出来的系统,显示的时间不正确然后被电商客户说卖二手,防火墙放行是因为默认系统会开启防火墙
baby666   
我记得改这个就一个注册表项,用批处理一条命令就行,不用这么复杂吧?不过折腾也好,越玩越会。支持折腾起来。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部