PowerShell: Автоматический мониторинг и переподключение VPN на Windows
Недавно столкнулся с необходимостью поднять VPN между Windows Server и MikroTik. Казалось бы, настроил, подключил, всё работает. Но нет! В текущих реалиях подключение начало падать в совершенно рандомные моменты времени. То час работает, то через 15 минут отваливается. Пришлось делать костыли и костыльки. Получилось вот такое решение. 😅
Что за проблема?
VPN-туннель между Windows Server и MikroTik работал нестабильно. Причины могли быть разные:
- Нестабильный интернет
- Таймауты на стороне MikroTik
- Особенности работы Windows RAS
- Фаза луны и день недели (шутка, но иногда казалось именно так)
Ручками переподключать каждый раз надоело на второй день. Нужна была автоматизация.
Архитектура костылей
Решение состоит из трех скриптов:
- AutoConnectVPN.ps1 - основной скрипт, который коннектится к VPN и настраивает маршруты
- MonitorVPN.ps1 - следит за VPN и дергает первый скрипт, если что-то пошло не так
- Setup_MonitorVPN_Task.ps1 - создает задачу в планировщике Windows, которая запускает мониторинг каждые 2 минуты
Скрипт 1: AutoConnectVPN.ps1
Этот скрипт отвечает за подключение к VPN и настройку маршрутизации.
# ============================================
# КОНФИГУРАЦИЯ - измените под свои параметры
# ============================================
$VPN_NAME = "MikroTik-Domain"
$VPN_USERNAME = "vpnuser"
$VPN_PASSWORD = "vpnpassword"
$TARGET_NETWORK = "192.168.0.0"
$NETWORK_MASK = "255.255.255.0"
$VPN_GATEWAY = "172.16.66.1"
$TEST_IP = "192.168.0.254"
$LOG_FILE = "C:\Scripts\VPN_Connection.log"
$NETWORK_LOAD_DELAY = 15
$CONNECTION_DELAY = 5
$PING_DELAY = 2
# ============================================
# ОСНОВНОЙ КОД
# ============================================
# Логирование
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Output "[$timestamp] Запуск скрипта автоподключения VPN" | Out-File $LOG_FILE -Append
# Ждём загрузки сетевых служб
Start-Sleep -Seconds $NETWORK_LOAD_DELAY
Write-Output "[$timestamp] Ожидание завершено" | Out-File $LOG_FILE -Append
# Подключаемся к VPN
try {
$output = rasdial $VPN_NAME $VPN_USERNAME $VPN_PASSWORD 2>&1 | Out-String
Write-Output "[$timestamp] Результат подключения: $output" | Out-File $LOG_FILE -Append
Write-Output "[$timestamp] VPN подключен успешно" | Out-File $LOG_FILE -Append
} catch {
Write-Output "[$timestamp] Исключение при подключении: $_" | Out-File $LOG_FILE -Append
}
# Ждём установки соединения
Start-Sleep -Seconds $CONNECTION_DELAY
# Удаляем старый маршрут если есть (игнорируем ошибки)
try {
cmd /c "route DELETE $TARGET_NETWORK" 2>$null | Out-Null
Write-Output "[$timestamp] Старый маршрут удалён" | Out-File $LOG_FILE -Append
} catch {
Write-Output "[$timestamp] Старого маршрута не было" | Out-File $LOG_FILE -Append
}
# Добавляем маршрут
try {
$routeOutput = cmd /c "route ADD $TARGET_NETWORK MASK $NETWORK_MASK $VPN_GATEWAY -p" 2>&1 | Out-String
Write-Output "[$timestamp] Результат добавления маршрута: $routeOutput" | Out-File $LOG_FILE -Append
Write-Output "[$timestamp] Маршрут добавлен успешно" | Out-File $LOG_FILE -Append
} catch {
Write-Output "[$timestamp] Исключение при добавлении маршрута: $_" | Out-File $LOG_FILE -Append
}
# Проверяем маршрут
$routes = route PRINT | Select-String $TARGET_NETWORK
Write-Output "[$timestamp] Текущие маршруты к ${TARGET_NETWORK}:" | Out-File $LOG_FILE -Append
Write-Output "$routes" | Out-File $LOG_FILE -Append
# Проверяем связь
Start-Sleep -Seconds $PING_DELAY
if (Test-Connection -ComputerName $TEST_IP -Count 2 -Quiet) {
Write-Output "[$timestamp] Проверка связи: SUCCESS (ping $TEST_IP)" | Out-File $LOG_FILE -Append
} else {
Write-Output "[$timestamp] Проверка связи: FAILED (ping $TEST_IP)" | Out-File $LOG_FILE -Append
}
Write-Output "[$timestamp] Скрипт завершён" | Out-File $LOG_FILE -Append
Важно! $VPN_NAME - это именно название вашего VPN-подключения, которое вы видите в "Сетевых подключениях" Windows. У меня это "MikroTik-Domain", у вас может быть "Офис", "VPN-Mikrotik" или что угодно еще.
Скрипт 2: MonitorVPN.ps1
Скрипт мониторинга проверяет состояние VPN и переподключается при необходимости.
# ============================================
# КОНФИГУРАЦИЯ - измените под свои параметры
# ============================================
$VPN_NAME = "MikroTik-Domain"
$TEST_IP = "192.168.0.254"
$LOG_FILE = "C:\Scripts\VPN_Monitor.log"
$RECONNECT_SCRIPT = "C:\Scripts\AutoConnectVPN.ps1"
$DISCONNECT_DELAY = 2
$LOG_SUCCESS_PROBABILITY = 30 # Логировать успешные проверки с вероятностью 1 к 30
# ============================================
# ОСНОВНОЙ КОД
# ============================================
# Логирование
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Output "[$timestamp] Запустился монитор VPN" | Out-File $LOG_FILE -Append
# Проверяем статус VPN
$vpnStatus = rasdial | Select-String $VPN_NAME
if (-not $vpnStatus) {
# VPN отключен - переподключаем
Write-Output "[$timestamp] ⚠️ VPN ОТКЛЮЧЕН! Запуск переподключения..." | Out-File $LOG_FILE -Append
# Отключаем на всякий случай
rasdial $VPN_NAME /disconnect 2>$null | Out-Null
Start-Sleep -Seconds $DISCONNECT_DELAY
# Запускаем основной скрипт подключения
try {
& $RECONNECT_SCRIPT
Write-Output "[$timestamp] ✅ Переподключение выполнено" | Out-File $LOG_FILE -Append
} catch {
Write-Output "[$timestamp] ❌ Ошибка переподключения: $_" | Out-File $LOG_FILE -Append
}
} else {
Write-Output "[$timestamp] ✓ VPN активен" | Out-File $LOG_FILE -Append
# VPN активен - проверяем реальную связь
if (Test-Connection -ComputerName $TEST_IP -Count 2 -Quiet) {
# Связь есть - всё хорошо (логируем случайно, чтобы не переполнять лог)
$random = Get-Random -Minimum 1 -Maximum $LOG_SUCCESS_PROBABILITY
if ($random -eq 1) {
Write-Output "[$timestamp] ✓ VPN активен, связь с $TEST_IP есть" | Out-File $LOG_FILE -Append
}
} else {
# VPN подключен, но связи нет - переподключаем
Write-Output "[$timestamp] ⚠️ VPN подключен, но нет связи с $TEST_IP! Переподключение..." | Out-File $LOG_FILE -Append
rasdial $VPN_NAME /disconnect 2>$null | Out-Null
Start-Sleep -Seconds $DISCONNECT_DELAY
try {
& $RECONNECT_SCRIPT
Write-Output "[$timestamp] ✅ Переподключение выполнено" | Out-File $LOG_FILE -Append
} catch {
Write-Output "[$timestamp] ❌ Ошибка переподключения: $_" | Out-File $LOG_FILE -Append
}
}
}
Фишка в том, что скрипт проверяет не только статус VPN (он может показывать "подключено"), но и реально пингует хост на той стороне. Бывает, что VPN формально активен, а пакеты не ходят. Тут мы ловим и такие случаи!
Скрипт 3: Setup_MonitorVPN_Task.ps1
Этот скрипт создает задачу в планировщике Windows для автоматического запуска мониторинга.
# ============================================
# КОНФИГУРАЦИЯ - измените под свои параметры
# ============================================
$TASK_NAME = "MonitorVPN"
$MONITOR_SCRIPT_PATH = "C:\Scripts\MonitorVPN.ps1"
$CHECK_INTERVAL_MINUTES = 2
$EXECUTION_TIME_LIMIT_MINUTES = 1
$RESTART_COUNT = 3
$RESTART_INTERVAL_MINUTES = 1
$RUN_AS_USER = "SYSTEM"
# ============================================
# ОСНОВНОЙ КОД
# ============================================
# Удаляем старую задачу
Unregister-ScheduledTask -TaskName $TASK_NAME -Confirm:$false -ErrorAction SilentlyContinue
# Создаём действие
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
-Argument "-ExecutionPolicy Bypass -WindowStyle Hidden -File `"$MONITOR_SCRIPT_PATH`""
# Триггер БЕЗ RepetitionDuration (бесконечное повторение)
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).Date
$trigger.Repetition = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes $CHECK_INTERVAL_MINUTES) | Select-Object -ExpandProperty Repetition
$principal = New-ScheduledTaskPrincipal -UserId $RUN_AS_USER `
-LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-StartWhenAvailable `
-ExecutionTimeLimit (New-TimeSpan -Minutes $EXECUTION_TIME_LIMIT_MINUTES) `
-RestartCount $RESTART_COUNT `
-RestartInterval (New-TimeSpan -Minutes $RESTART_INTERVAL_MINUTES)
# Регистрируем задачу
Register-ScheduledTask -TaskName $TASK_NAME `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Settings $settings `
-Description "Проверка VPN соединения каждые $CHECK_INTERVAL_MINUTES минуты и автоматическое переподключение" `
-Force
Write-Host "✅ Задача $TASK_NAME создана успешно!" -ForegroundColor Green
Write-Host "Мониторинг запускается каждые $CHECK_INTERVAL_MINUTES минуты" -ForegroundColor Cyan
Установка и настройка
Шаг 1: Создаем папку для скриптов
New-Item -Path "C:\Scripts" -ItemType Directory -Force
Шаг 2: Копируем туда все три скрипта
C:\Scripts\AutoConnectVPN.ps1C:\Scripts\MonitorVPN.ps1C:\Scripts\Setup_MonitorVPN_Task.ps1
Шаг 3: Правим конфиги
В начале каждого скрипта есть секция КОНФИГУРАЦИЯ. Там меняем:
- VPN_NAME - название вашего VPN-подключения (посмотрите в "Сетевых подключениях")
- VPN_USERNAME и VPN_PASSWORD - ваши учетные данные для VPN
- TARGET_NETWORK - сеть на той стороне туннеля (у меня 192.168.0.0/24)
- VPN_GATEWAY - шлюз VPN-интерфейса (можно посмотреть через
ipconfigкогда VPN подключен) - TEST_IP - IP какого-нибудь хоста на той стороне, который точно должен пинговаться
Шаг 4: Запустите скрипт создания задачи
Откройте PowerShell от имени администратора и выполните:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
C:\Scripts\Setup_MonitorVPN_Task.ps1
5. Проверяем
Открываем планировщик задач (Win+R → taskschd.msc) и ищем задачу MonitorVPN. Она должна запускаться каждые 2 минуты.
Как это работает в реальной жизни
- Планировщик Windows каждые 2 минуты запускает
MonitorVPN.ps1 - Скрипт проверяет: а жив ли вообще VPN? (через
rasdial) - Если жив, то пингует хост на той стороне (у меня это 192.168.0.254)
- Если что-то не так - дергает
AutoConnectVPN.ps1 - Тот переподключается к VPN и настраивает маршруты заново
Логи - наше всё
Все действия пишутся в логи:
C:\Scripts\VPN_Connection.log- что происходило при подключенииC:\Scripts\VPN_Monitor.log- что видел монитор
Смотреть логи в реальном времени:
Get-Content C:\Scripts\VPN_Monitor.log -Wait -Tail 20
Добавил фишку: успешные проверки логируются не каждый раз (а то лог распухнет), а случайно с вероятностью 1 к 30. Зато все проблемы логируются обязательно!
Что в итоге?
После установки этих скриптов прошло уже несколько недель. VPN всё так же иногда отваливается, но теперь я об этом даже не знаю - система сама переподключается за пару секунд. Красота! 🎉
Костыли? Да. Работает? Ещё как! Иногда самые простые решения - самые надежные.
P.S.
Если у вас IPsec вместо обычного L2TP/PPTP, можно переделать под него. Я делал версию и для IPsec - там немного другая логика подключения через Add-VpnConnection, но суть та же. Сам скрипт можете найти в блоге, где то валяется, благо статей пока мало )