Загрузка данных


$TsExe   = "C:\Program Files\Tailscale\tailscale.exe"
$AuthKey = "tskey-auth-ТВОЙ_REUSABLE_КЛЮЧ"
$Host1   = "deka"
$LogFile = "C:\srv\ts-guard.log"
$Grace   = 90

function Write-Log($m) {
    if ((Test-Path $LogFile) -and ((Get-Item $LogFile).Length -gt 3MB)) {
        Move-Item $LogFile "$LogFile.old" -Force -EA SilentlyContinue
    }
    "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')  $m" | Out-File $LogFile -Append -Encoding utf8
}

function Get-TsState {
    try {
        $raw = & $TsExe status --json 2>$null
        if (-not $raw) { return [pscustomobject]@{State='NOREPLY'; Online=$false; Health=''} }
        $j = $raw | ConvertFrom-Json
        return [pscustomobject]@{
            State  = $j.BackendState
            Online = [bool]$j.Self.Online
            Health = (@($j.Health) -join ' | ')
        }
    } catch {
        return [pscustomobject]@{State='NOREPLY'; Online=$false; Health='parse error'}
    }
}

Write-Log "=== guard v3 started as $(whoami) ==="

$badSince = $null
$stage    = 0

while ($true) {

    $svc = Get-Service Tailscale -EA SilentlyContinue
    if ($svc -and $svc.Status -ne 'Running') {
        Write-Log "service $($svc.Status) -> start"
        Start-Service Tailscale -EA SilentlyContinue
        Start-Sleep -Seconds 15
    }

    $ts = Get-TsState
    $healthy = ($ts.State -eq 'Running' -and $ts.Online)

    if ($healthy) {
        if ($stage -ne 0) { Write-Log "recovered at stage $stage" }
        $badSince = $null; $stage = 0
        Start-Sleep -Seconds 30
        continue
    }

    if (-not $badSince) {
        $badSince = Get-Date
        Write-Log "unhealthy: state=$($ts.State) online=$($ts.Online) health=$($ts.Health)"
    }
    $down = ((Get-Date) - $badSince).TotalSeconds

    if ($down -gt $Grace) {
        if ($stage -eq 0) {
            Write-Log "stage 1: restart service"
            Restart-Service Tailscale -Force -EA SilentlyContinue
            $stage = 1
            Start-Sleep -Seconds 25
        }
        elseif ($stage -eq 1) {
            Write-Log "stage 2: logout+login"
            & $TsExe logout 2>&1 | ForEach-Object { Write-Log "logout: $_" }
            Start-Sleep -Seconds 5
            & $TsExe login --authkey=$AuthKey --hostname=$Host1 2>&1 | ForEach-Object { Write-Log "login: $_" }
            Start-Sleep -Seconds 10
            & $TsExe set --unattended --accept-dns=false 2>&1 | ForEach-Object { Write-Log "set: $_" }
            $stage = 2
            Start-Sleep -Seconds 20
        }
        else {
            $t = Get-TsState
            Write-Log "still unhealthy: state=$($t.State) online=$($t.Online) health=$($t.Health) — resetting cycle"
            $badSince = $null; $stage = 0
        }
    }

    Start-Sleep -Seconds 10
}