02
2025
12

分享一个定时检查网址,在网站不可访问时自动重启花生壳客户端的脚本

    我的这个小站早些年用的是每步的内网穿透,每步消失后就改用花生壳的内网穿透,后来干脆趁花生壳搞活动充值了花生壳的专业版会员,目前也稳定运行了很多年了。花生壳服务稳定性方面还好,虽然小水管只提供1MB的带宽,但对本站来说,就一个Blog,也足够用了。但他的终端应用程序实在是不敢恭维,经常莫名其妙的就闪退或掉线,有时候网站突然无法访问了,远程登录到服务器,发现花生壳程序的进程莫名其妙又不知所踪。所以从很多年前开始,我就一直在后台还运行一个定时重启花生壳的计划任务,指定运行一个重启花生壳的批处理BAT。

分享一个定时检查网址,在网站不可访问时自动重启花生壳客户端的脚本

    早先的批处理程序很简单,KILL掉全部花生壳进程,然后重启花生壳就可以了,总共就7行。重启频率可以在计划任务里调整,后来我保持一个小时重启一次的频率,基本是够用的。但这样处理有些问题,首先就是大部分时间是不需要重启的,绝大部分时间网站访问都是正常的,这个时候重启,其实是人为降低了网站可用性,尽管影响微乎其微吧。其次就是每次kill进程,花生壳的系统托盘图标都不会自动清理,有时候几十天才访问一次服务器,会发现系统托盘里积累了几百个花生壳图标,点开系统托盘能把半个屏幕占满,也是非常让人不爽。在这次把小站搬迁到Windows Server 2019后,刚好花生壳也进化到新的版本,我认为花生壳闪退、掉线的问题应该有所好转吧,所以我没有再使用以前的批处理去重启花生壳……结果证明花生壳的老传统被带到了新版本上,仍然会一段时间后闪退掉线。。。

分享一个定时检查网址,在网站不可访问时自动重启花生壳客户端的脚本

    于是这次整个将批处理程序升级为一个PowerShell脚本,实现三个目标,首先是定时检查网站可访问状态,并且不能仅通过ping,需要检测网站内容是否正常。其次是可以在发现网站不可达状态后,重启花生壳。最后是在重启花生壳无效的情况下,重启服务器。目前这三个目标都实现了,检测网站状态的时候会提前清空本地DNS缓存,防止误判,并且会检测多次以确保不会错误执行重启,同时我在脚本里增加了每7天重启服务器,以确保服务器整体状态良好,同时脚本会在同目录下生成一个日志文件,以辅助自己检查问题所在。

分享一个定时检查网址,在网站不可访问时自动重启花生壳客户端的脚本

    按照惯例,分享一下:

# 脚本名称: HskDDNS_Website_Monitor_Enhanced.ps1
# 描述: 监控网站可访问性并检查页面标题,管理HskDDNS进程,包含24小时定时重启,每次检测前清空DNS缓存,启动时立即重启HskDDNS
# 需要管理员权限运行
# 脚本配置
$Config = @{
    WebsiteUrl = "http://www.lainzy.net" # 要监控的网站URL
    WebsiteUrlAlternative = "http://lainzy.oicp.net" # 备用HTTP URL
    DDNS_Path = "C:\Program Files (x86)\Oray\HskDDNS\HskDDNS.exe" # DDNS程序路径
    CheckInterval = 30 * 60 # 检查间隔30分钟(秒)
    ScheduledRestartInterval = 7 * 24 * 60 * 60 # 定时重启间隔24小时(秒)
    RetryCount = 3 # 最大重试次数
    RetryDelay = 10 # 重试延迟(秒)
    RestartDelay = 3 * 60 # 重启进程后等待时间(秒)
    LogFile = "$PSScriptRoot\HskDDNS_Monitor_Enhanced.log" # 日志文件路径
    MaxLogSize = 3MB # 日志文件最大大小
    ExpectedTitle = "阳光明媚" # 期望的页面标题包含的文本
    CheckTitle = $true # 是否检查页面标题
    MaxContentSize = 10240 # 最大内容读取大小(字节)
    TimeoutSeconds = 10 # 请求超时时间
    ClearDNSCacheBeforeCheck = $true # 检查前清空DNS缓存
    RestartOnScriptStart = $true # 脚本启动时立即重启HskDDNS
}
# 初始化
$ErrorActionPreference = "Continue"
$global:WebsiteCheckFailed = $false
$global:DDNSRestarted = $false
$global:CheckCounter = 0
$global:LastRestartTime = $null
$global:LastScheduledRestartTime = Get-Date
$global:NextScheduledRestartTime = (Get-Date).AddSeconds($Config.ScheduledRestartInterval)
# 函数:写入日志
function Write-Log {
    param(
        [string]$Message,
        [string]$Level = "INFO"
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$timestamp] [$Level] $Message"
    
    # 输出到控制台
    switch ($Level) {
        "ERROR" { Write-Host $logEntry -ForegroundColor Red }
        "WARNING" { Write-Host $logEntry -ForegroundColor Yellow }
        "SUCCESS" { Write-Host $logEntry -ForegroundColor Green }
        default { Write-Host $logEntry -ForegroundColor White }
    }
    
    # 写入日志文件
    try {
        # 检查日志文件大小,如果超过限制则清空
        if (Test-Path $Config.LogFile) {
            $logSize = (Get-Item $Config.LogFile).Length
            if ($logSize -gt $Config.MaxLogSize) {
                Clear-Content $Config.LogFile -Force
                "[$timestamp] [INFO] 日志文件已清理" | Out-File $Config.LogFile -Append -Encoding UTF8
            }
        }
        
        $logEntry | Out-File $Config.LogFile -Append -Encoding UTF8
    }
    catch {
        Write-Host "无法写入日志文件: $_" -ForegroundColor Red
    }
}
# 函数:清空DNS缓存(修复WMI方法)
function Clear-DNSCache {
    Write-Log "开始清空本地DNS缓存..."
    
    $methods = @()
    
    try {
        # 方法1: 使用Clear-DnsClientCache (PowerShell 5.1+)
        if (Get-Command -Name Clear-DnsClientCache -ErrorAction SilentlyContinue) {
            Write-Log "使用方法1: Clear-DnsClientCache..."
            Clear-DnsClientCache -ErrorAction Stop
            $methods += "Clear-DnsClientCache"
            Write-Log "DNS缓存已清空 (方法1)" "SUCCESS"
        }
    }
    catch {
        Write-Log "方法1失败: $($_.Exception.Message)" "WARNING"
    }
    
    try {
        # 方法2: 使用ipconfig /flushdns
        Write-Log "使用方法2: ipconfig /flushdns..."
        $ipconfigResult = ipconfig /flushdns 2>&1
        if ($LASTEXITCODE -eq 0) {
            $methods += "ipconfig"
            Write-Log "DNS缓存已清空 (方法2): $ipconfigResult" "SUCCESS"
        }
        else {
            Write-Log "ipconfig /flushdns失败: $ipconfigResult" "WARNING"
        }
    }
    catch {
        Write-Log "方法2失败: $($_.Exception.Message)" "WARNING"
    }
    
    try {
        # 方法3: 使用WMI清除DNS缓存
        Write-Log "使用方法3: WMI清除DNS缓存..."
        
        # 使用Invoke-WmiMethod调用ClearDNSServerCache方法
        $adapters = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled = True" -ErrorAction Stop
        
        foreach ($adapter in $adapters) {
            try {
                # 使用Invoke-WmiMethod来调用ClearDNSServerCache方法
                $result = Invoke-WmiMethod -InputObject $adapter -Name ClearDNSServerCache -ErrorAction Stop
                
                if ($result.ReturnValue -eq 0) {
                    $methods += "WMI"
                    Write-Log "网络适配器 $($adapter.Description) DNS缓存已清空 (返回码: $($result.ReturnValue))" "SUCCESS"
                }
                else {
                    Write-Log "网络适配器 $($adapter.Description) DNS缓存清空失败 (返回码: $($result.ReturnValue))" "WARNING"
                }
            }
            catch {
                Write-Log "WMI方法调用失败: $($_.Exception.Message)" "WARNING"
            }
        }
    }
    catch {
        Write-Log "方法3失败: $($_.Exception.Message)" "WARNING"
    }
    
    try {
        # 方法4: 使用DnsClient PowerShell模块
        Write-Log "使用方法4: DnsClient模块清除缓存..."
        if (Get-Module -Name DnsClient -ListAvailable -ErrorAction SilentlyContinue) {
            Import-Module DnsClient -ErrorAction SilentlyContinue
            Clear-DnsClientCache -ErrorAction SilentlyContinue
            $methods += "DnsClient模块"
            Write-Log "DNS缓存已清空 (方法4)" "SUCCESS"
        }
    }
    catch {
        Write-Log "方法4失败: $($_.Exception.Message)" "WARNING"
    }
    
    # 强制等待DNS缓存刷新
    Write-Log "等待DNS缓存刷新完成..."
    Start-Sleep -Seconds 2
    
    # 验证DNS缓存是否已清空
    try {
        # 尝试解析一个域名来验证DNS是否正常工作
        $testResult = Resolve-DnsName -Name "www.microsoft.com" -ErrorAction SilentlyContinue
        if ($testResult) {
            Write-Log "DNS解析测试成功,DNS服务正常" "SUCCESS"
        }
        else {
            Write-Log "DNS解析测试未返回结果" "WARNING"
        }
    }
    catch {
        Write-Log "DNS解析测试失败,但可能只是临时问题: $_" "WARNING"
    }
    
    if ($methods.Count -gt 0) {
        Write-Log "DNS缓存清空完成,使用了以下方法: $($methods -join ', ')" "SUCCESS"
        return $true
    }
    else {
        Write-Log "所有DNS缓存清空方法都失败了" "ERROR"
        return $false
    }
}
# 函数:检查页面标题
function Test-PageTitle {
    param(
        [string]$Content,
        [string]$ExpectedText
    )
    
    if ([string]::IsNullOrWhiteSpace($Content)) {
        Write-Log "页面内容为空,无法检查标题" "WARNING"
        return $false
    }
    
    # 提取<title>标签内容
    $titleMatch = [regex]::Match($Content, '<title[^>]*>([^<]+)</title>', [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
    
    if ($titleMatch.Success) {
        $title = $titleMatch.Groups[1].Value
        Write-Log "找到页面标题: $title"
        
        # 检查标题是否包含预期文本
        if ($title -match [regex]::Escape($ExpectedText)) {
            Write-Log "页面标题包含预期文本 '$ExpectedText'" "SUCCESS"
            return $true
        }
        else {
            Write-Log "页面标题不包含预期文本 '$ExpectedText'" "WARNING"
            return $false
        }
    }
    else {
        Write-Log "未找到页面标题标签" "WARNING"
        
        # 如果没有找到<title>标签,检查整个页面内容是否包含预期文本
        if ($Content -match [regex]::Escape($ExpectedText)) {
            Write-Log "页面内容包含预期文本 '$ExpectedText' (但未找到<title>标签)" "SUCCESS"
            return $true
        }
        else {
            Write-Log "页面内容不包含预期文本 '$ExpectedText'" "WARNING"
            return $false
        }
    }
}
# 函数:使用GET方法检查网站并验证标题
function Test-WebsiteWithTitleCheck {
    param(
        [string]$Url
    )
    
    $maxRetries = $Config.RetryCount
    $retryDelay = $Config.RetryDelay
    
    for ($i = 1; $i -le $maxRetries; $i++) {
        try {
            Write-Log "尝试第 $i/$maxRetries 次访问网站并检查标题: $Url"
            
            # 创建Web请求对象,以便更好地控制
            $request = [System.Net.HttpWebRequest]::Create($Url)
            $request.Method = "GET"
            $request.Timeout = $Config.TimeoutSeconds * 1000 # 毫秒
            $request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
            $request.AllowAutoRedirect = $true
            
            # 设置只读取部分内容以加快速度
            $request.AddRange(0, $Config.MaxContentSize - 1)
            
            # 发送请求
            $response = $request.GetResponse()
            
            # 检查状态码
            if ($response.StatusCode -eq 200) {
                Write-Log "网站请求成功 (HTTP状态: $($response.StatusCode))"
                
                # 读取响应内容
                $stream = $response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($stream, [System.Text.Encoding]::UTF8)
                $content = $reader.ReadToEnd()
                $reader.Close()
                $response.Close()
                
                Write-Log "读取内容长度: $($content.Length) 字符"
                
                # 检查页面标题
                if ($Config.CheckTitle) {
                    $titleValid = Test-PageTitle -Content $content -ExpectedText $Config.ExpectedTitle
                    
                    if ($titleValid) {
                        Write-Log "网站访问成功且标题验证通过" "SUCCESS"
                        return $true
                    }
                    else {
                        Write-Log "网站返回200状态码,但标题验证失败" "WARNING"
                        return $false
                    }
                }
                else {
                    Write-Log "网站访问成功 (跳过标题检查)" "SUCCESS"
                    return $true
                }
            }
            else {
                Write-Log "网站返回非200状态码: $($response.StatusCode)" "WARNING"
                $response.Close()
                return $false
            }
        }
        catch [System.Net.WebException] {
            $webEx = $_.Exception
            
            if ($webEx.Response) {
                $statusCode = [int]$webEx.Response.StatusCode
                $responseStream = $webEx.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($responseStream)
                $errorContent = $reader.ReadToEnd()
                $reader.Close()
                $webEx.Response.Close()
                
                Write-Log "Web异常 (状态码: $statusCode): $($webEx.Message)" "WARNING"
                Write-Log "错误响应内容: $($errorContent.Substring(0, [Math]::Min(200, $errorContent.Length)))..."
                
                # 如果是404,可能网站不存在
                if ($statusCode -eq 404) {
                    Write-Log "网站返回404,页面不存在" "WARNING"
                }
            }
            else {
                Write-Log "网络错误: $($webEx.Message)" "WARNING"
            }
        }
        catch {
            Write-Log "访问网站时发生错误: $($_.Exception.Message)" "WARNING"
            Write-Log "错误类型: $($_.Exception.GetType().FullName)" "WARNING"
        }
        
        # 如果不是最后一次尝试,则等待
        if ($i -lt $maxRetries) {
            Write-Log "等待 $retryDelay 秒后重试..."
            Start-Sleep -Seconds $retryDelay
        }
    }
    
    Write-Log "检测失败: 所有重试尝试均失败" "WARNING"
    return $false
}
# 函数:备用检测方法 - 使用Test-Connection (Ping)
function Test-WebsiteWithPing {
    param(
        [string]$Url
    )
    
    # 从URL中提取主机名
    $uri = [Uri]$Url
    $hostname = $uri.Host
    
    Write-Log "尝试使用Ping检测主机: $hostname"
    
    try {
        $pingResult = Test-Connection -ComputerName $hostname -Count 2 -Quiet -ErrorAction Stop
        
        if ($pingResult) {
            Write-Log "Ping检测成功: $hostname" "SUCCESS"
            return $true
        }
        else {
            Write-Log "Ping检测失败: $hostname" "WARNING"
            return $false
        }
    }
    catch {
        Write-Log "Ping检测出错: $($_.Exception.Message)" "WARNING"
        return $false
    }
}
# 函数:综合检测网站可访问性
function Test-WebsiteAccessibility {
    param(
        [string]$Url
    )
    
    # 使用GET方法并检查标题
    $titleCheckResult = Test-WebsiteWithTitleCheck -Url $Url
    
    if ($titleCheckResult) {
        return $true
    }
    
    Write-Log "标题检查失败,尝试Ping检测作为备用" "WARNING"
    
    # 如果标题检查失败,尝试Ping检测
    $pingResult = Test-WebsiteWithPing -Url $Url
    return $pingResult
}
# 函数:快速检测(仅检查状态码,不检查标题)
function Test-WebsiteQuick {
    param(
        [string]$Url
    )
    
    try {
        Write-Log "快速检测网站: $Url"
        
        # 使用HEAD方法快速检查
        $response = Invoke-WebRequest -Uri $Url -Method Head -TimeoutSec 5 -ErrorAction Stop
        
        if ($response.StatusCode -eq 200) {
            Write-Log "快速检测成功 (HTTP状态: 200)" "SUCCESS"
            return $true
        }
        else {
            Write-Log "快速检测失败 (HTTP状态: $($response.StatusCode))" "WARNING"
            return $false
        }
    }
    catch {
        Write-Log "快速检测失败: $($_.Exception.Message)" "WARNING"
        return $false
    }
}
# 函数:检查并重启HskDDNS进程
function Restart-HskDDNS {
    param(
        [string]$Reason = "未知原因"
    )
    
    Write-Log "开始处理HskDDNS进程 (原因: $Reason)"
    
    # 1. 关闭现有进程
    $processes = Get-Process -Name "HskDDNS" -ErrorAction SilentlyContinue
    if ($processes) {
        Write-Log "找到 $($processes.Count) 个HskDDNS进程,正在关闭..."
        foreach ($process in $processes) {
            try {
                Stop-Process -Id $process.Id -Force -ErrorAction Stop
                Write-Log "已关闭进程 (PID: $($process.Id))" "SUCCESS"
            }
            catch {
                Write-Log "关闭进程失败 (PID: $($process.Id)): $_" "ERROR"
            }
        }
        
        # 等待进程完全退出
        Start-Sleep -Seconds 2
        
        # 确认进程已关闭
        $remaining = Get-Process -Name "HskDDNS" -ErrorAction SilentlyContinue
        if ($remaining) {
            Write-Log "警告:仍有HskDDNS进程在运行" "WARNING"
        }
    }
    else {
        Write-Log "未找到运行的HskDDNS进程"
    }
    
    # 2. 检查程序文件是否存在
    if (-not (Test-Path $Config.DDNS_Path)) {
        Write-Log "错误:找不到HskDDNS程序文件: $($Config.DDNS_Path)" "ERROR"
        return $false
    }
    
    # 3. 重新启动程序
    try {
        Write-Log "正在启动HskDDNS程序..."
        $processInfo = New-Object System.Diagnostics.ProcessStartInfo
        $processInfo.FileName = $Config.DDNS_Path
        $processInfo.WorkingDirectory = Split-Path $Config.DDNS_Path -Parent
        $processInfo.UseShellExecute = $true
        
        $process = [System.Diagnostics.Process]::Start($processInfo)
        
        if ($process) {
            Write-Log "HskDDNS程序已启动 (PID: $($process.Id))" "SUCCESS"
            $global:DDNSRestarted = $true
            $global:LastRestartTime = Get-Date
            return $true
        }
        else {
            Write-Log "启动HskDDNS程序失败" "ERROR"
            return $false
        }
    }
    catch {
        Write-Log "启动HskDDNS程序时出错: $_" "ERROR"
        return $false
    }
}
# 函数:检查并执行定时重启
function Check-And-PerformScheduledRestart {
    $currentTime = Get-Date
    
    # 检查是否达到定时重启时间
    if ($currentTime -ge $global:NextScheduledRestartTime) {
        Write-Log "达到24小时定时重启时间,执行定时重启..." "WARNING"
        Write-Log "上次定时重启时间: $($global:LastScheduledRestartTime.ToString('yyyy-MM-dd HH:mm:ss'))"
        Write-Log "本次定时重启时间: $($currentTime.ToString('yyyy-MM-dd HH:mm:ss'))"
        
        # 执行定时重启
        $restartResult = Restart-HskDDNS -Reason "24小时定时重启"
        
        if ($restartResult) {
            # 更新定时重启时间
            $global:LastScheduledRestartTime = $currentTime
            $global:NextScheduledRestartTime = $currentTime.AddSeconds($Config.ScheduledRestartInterval)
            Write-Log "定时重启完成,下次定时重启时间: $($global:NextScheduledRestartTime.ToString('yyyy-MM-dd HH:mm:ss'))" "SUCCESS"
        }
        else {
            Write-Log "定时重启失败" "ERROR"
        }
        
        return $true
    }
    
    return $false
}
# 函数:重启系统
function Restart-System {
    Write-Log "准备重启系统..." "WARNING"
    
    # 显示倒计时
    $countdown = 30
    while ($countdown -gt 0) {
        Write-Host "系统将在 $countdown 秒后重启,按 Ctrl+C 取消..." -ForegroundColor Yellow
        Start-Sleep -Seconds 1
        $countdown--
    }
    
    Write-Log "正在重启系统..." "WARNING"
    
    try {
        # 使用不同的方法重启系统
        Restart-Computer -Force -ErrorAction Stop
        Write-Log "重启命令已执行" "WARNING"
    }
    catch {
        Write-Log "使用Restart-Computer失败,尝试使用shutdown命令..." "WARNING"
        try {
            shutdown /r /t 5 /c "HskDDNS监控脚本:网站无法访问,系统正在重启"
            Write-Log "shutdown命令已执行" "WARNING"
        }
        catch {
            Write-Log "所有重启方法都失败: $_" "ERROR"
        }
    }
}
# 函数:显示定时重启倒计时
function Show-ScheduledRestartCountdown {
    $currentTime = Get-Date
    $timeRemaining = $global:NextScheduledRestartTime - $currentTime
    
    if ($timeRemaining.TotalSeconds -le 0) {
        return "定时重启: 即将执行"
    }
    
    $hours = [math]::Floor($timeRemaining.TotalHours)
    $minutes = [math]::Floor($timeRemaining.TotalMinutes % 60)
    $seconds = [math]::Floor($timeRemaining.TotalSeconds % 60)
    
    return "定时重启倒计时: ${hours}小时${minutes}分钟${seconds}秒"
}
# 函数:脚本启动初始化
function Initialize-ScriptStart {
    Write-Log "=== 脚本启动初始化 ===" "SUCCESS"
    
    if ($Config.RestartOnScriptStart) {
        Write-Log "脚本启动时立即重启HskDDNS进程..."
        $initRestartResult = Restart-HskDDNS -Reason "脚本启动初始化"
        
        if ($initRestartResult) {
            Write-Log "脚本启动初始化完成,HskDDNS已重启" "SUCCESS"
        }
        else {
            Write-Log "脚本启动初始化失败,但仍将继续运行" "ERROR"
        }
        
        # 等待一段时间让程序稳定
        Write-Log "等待15秒让HskDDNS程序稳定..."
        Start-Sleep -Seconds 15
    }
    else {
        Write-Log "跳过脚本启动时的HskDDNS重启(配置已禁用)"
    }
    
    Write-Log "脚本初始化完成,开始主监控循环" "SUCCESS"
}
# 函数:主监控循环
function Start-WebsiteMonitoring {
    Write-Log "=== 主监控循环启动 ===" "SUCCESS"
    Write-Log "监控网站: $($Config.WebsiteUrl)"
    Write-Log "检测方法: GET请求 + 标题检查 (包含 '$($Config.ExpectedTitle)')"
    Write-Log "DNS缓存清空: $($Config.ClearDNSCacheBeforeCheck)"
    Write-Log "检查间隔: $($Config.CheckInterval/60) 分钟"
    Write-Log "定时重启间隔: $($Config.ScheduledRestartInterval/3600) 小时"
    Write-Log "下次定时重启时间: $($global:NextScheduledRestartTime.ToString('yyyy-MM-dd HH:mm:ss'))"
    Write-Log "日志文件: $($Config.LogFile)"
    Write-Log "="
    
    while ($true) {
        $global:CheckCounter++
        
        # 显示状态信息
        $countdownInfo = Show-ScheduledRestartCountdown
        Write-Log "第 $global:CheckCounter 次检查开始 - $countdownInfo"
        
        # 1. 检查并执行定时重启(如果有需要)
        $scheduledRestartPerformed = Check-And-PerformScheduledRestart
        
        # 如果刚刚执行了定时重启,等待一小段时间让程序稳定
        if ($scheduledRestartPerformed) {
            Write-Log "等待10秒让HskDDNS程序稳定..."
            Start-Sleep -Seconds 10
        }
        
        # 2. 清空DNS缓存(如果配置启用)
        if ($Config.ClearDNSCacheBeforeCheck) {
            Write-Log "清空DNS缓存以确保检测准确性..."
            $dnsCleared = Clear-DNSCache
            
            if ($dnsCleared) {
                Write-Log "DNS缓存已清空,准备进行网站检测" "SUCCESS"
            }
            else {
                Write-Log "DNS缓存清空失败,但仍将继续进行网站检测" "WARNING"
            }
        }
        else {
            Write-Log "跳过DNS缓存清空(配置已禁用)"
        }
        
        # 3. 进行网站检测
        Write-Log "进行快速检测(仅检查状态码)..."
        $quickCheckResult = Test-WebsiteQuick -Url $Config.WebsiteUrl
        
        if (-not $quickCheckResult -and $Config.WebsiteUrlAlternative) {
            Write-Log "HTTP快速检测失败,尝试HTTPS..."
            $quickCheckResult = Test-WebsiteQuick -Url $Config.WebsiteUrlAlternative
        }
        
        if ($quickCheckResult) {
            Write-Log "快速检测通过,进行完整检测..."
            
            # 完整检测(检查标题)
            $websiteAccessible = Test-WebsiteAccessibility -Url $Config.WebsiteUrl
            
            # 如果HTTP访问失败,尝试HTTPS
            if (-not $websiteAccessible -and $Config.WebsiteUrlAlternative) {
                Write-Log "HTTP完整检测失败,尝试HTTPS..."
                $websiteAccessible = Test-WebsiteAccessibility -Url $Config.WebsiteUrlAlternative
            }
        }
        else {
            Write-Log "快速检测失败,跳过完整检测"
            $websiteAccessible = $false
        }
        
        if ($websiteAccessible) {
            Write-Log "网站可访问性检查通过" "SUCCESS"
            $global:WebsiteCheckFailed = $false
        }
        else {
            Write-Log "网站无法访问或标题验证失败" "ERROR"
            
            # 第一次检测到失败(且不是因为定时重启)
            if (-not $global:WebsiteCheckFailed -and -not $scheduledRestartPerformed) {
                Write-Log "首次检测到网站不可访问,重启HskDDNS进程"
                $global:WebsiteCheckFailed = $true
                $restartSuccess = Restart-HskDDNS -Reason "网站不可访问"
                
                if ($restartSuccess) {
                    Write-Log "等待 $($Config.RestartDelay/60) 分钟后再次检查网站..."
                    Start-Sleep -Seconds $Config.RestartDelay
                    
                    # 再次检查网站前清空DNS缓存
                    if ($Config.ClearDNSCacheBeforeCheck) {
                        Write-Log "重启后再次清空DNS缓存..."
                        Clear-DNSCache
                    }
                    
                    # 再次检查网站
                    Write-Log "重新检查网站可访问性..."
                    $websiteAccessibleAfterRestart = Test-WebsiteAccessibility -Url $Config.WebsiteUrl
                    
                    if (-not $websiteAccessibleAfterRestart -and $Config.WebsiteUrlAlternative) {
                        $websiteAccessibleAfterRestart = Test-WebsiteAccessibility -Url $Config.WebsiteUrlAlternative
                    }
                    
                    if (-not $websiteAccessibleAfterRestart) {
                        Write-Log "重启HskDDNS后网站仍然无法访问,准备重启系统..." "ERROR"
                        Restart-System
                    }
                    else {
                        Write-Log "重启HskDDNS后网站恢复访问" "SUCCESS"
                        $global:WebsiteCheckFailed = $false
                    }
                }
            }
            else {
                if ($scheduledRestartPerformed) {
                    Write-Log "网站检测失败,但刚刚已执行定时重启" "WARNING"
                }
                else {
                    Write-Log "网站持续无法访问,但上次已处理过" "WARNING"
                }
            }
        }
        
        # 计算下一次检查的时间
        $nextCheckTime = (Get-Date).AddSeconds($Config.CheckInterval)
        Write-Log "下一次网站检查时间: $($nextCheckTime.ToString('HH:mm:ss'))"
        Write-Log "下一次定时重启时间: $($global:NextScheduledRestartTime.ToString('yyyy-MM-dd HH:mm:ss'))"
        Write-Log "-" * 50
        
        # 等待下一次检查
        Start-Sleep -Seconds $Config.CheckInterval
    }
}
# 主程序入口
try {
    # 检查管理员权限
    $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
    if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Write-Host "请使用管理员权限运行此脚本!" -ForegroundColor Red
        Write-Host "右键点击脚本,选择'以管理员身份运行'" -ForegroundColor Yellow
        pause
        exit 1
    }
    
    # 检查必要的模块
    if ($PSVersionTable.PSVersion.Major -lt 3) {
        Write-Host "需要PowerShell 3.0或更高版本" -ForegroundColor Red
        exit 1
    }
    
    # 创建日志目录
    $logDir = Split-Path $Config.LogFile -Parent
    if (-not (Test-Path $logDir)) {
        New-Item -ItemType Directory -Path $logDir -Force | Out-Null
    }
    
    # 显示脚本信息
    Write-Host "=========================================" -ForegroundColor Cyan
    Write-Host "HskDDNS监控脚本 (增强版)" -ForegroundColor Cyan
    Write-Host "网站检测间隔: $($Config.CheckInterval/60) 分钟" -ForegroundColor Cyan
    Write-Host "定时重启间隔: $($Config.ScheduledRestartInterval/3600) 小时" -ForegroundColor Cyan
    Write-Host "DNS缓存清空: $($Config.ClearDNSCacheBeforeCheck)" -ForegroundColor Cyan
    Write-Host "启动时重启HskDDNS: $($Config.RestartOnScriptStart)" -ForegroundColor Cyan
    Write-Host "下次定时重启: $($global:NextScheduledRestartTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Cyan
    Write-Host "日志文件: $($Config.LogFile)" -ForegroundColor Cyan
    Write-Host "=========================================" -ForegroundColor Cyan
    Write-Host ""
    
    # 测试标题检查函数
    Write-Log "测试标题检查功能..."
    $testContent = '<html><head><title>阳光明媚的个人网站</title></head><body>欢迎</body></html>'
    $titleCheckResult = Test-PageTitle -Content $testContent -ExpectedText $Config.ExpectedTitle
    Write-Log "标题检查测试结果: $titleCheckResult"
    
    # 脚本启动初始化(包括立即重启HskDDNS)
    Initialize-ScriptStart
    
    # 启动监控
    Start-WebsiteMonitoring
}
catch {
    Write-Log "脚本发生错误: $_" "ERROR"
    Write-Log "堆栈跟踪: $($_.ScriptStackTrace)" "ERROR"
    pause
}
finally {
    Write-Log "脚本停止" "WARNING"
}

分享一个定时检查网址,在网站不可访问时自动重启花生壳客户端的脚本HskDDNS_Website_Monitor_Enhanced.rar

    脚本需要在管理员权限下运行。有需要的自取,至于脚本中哪里需要调整,那就自便。

    如果要开机自动执行,可以加入计划任务,也可以通过其他方式,这个就看你个人喜欢了。总之希望这个东西对那些被同样问题困扰的朋友有点帮助吧……分享一个定时检查网址,在网站不可访问时自动重启花生壳客户端的脚本

« 上一篇

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

召唤伊斯特瓦尔