Как автоматизировать Cisco AnyConnect и забыть про ручное переключение VPN

Написано

в

Проблема: рутина при смене сетей

Когда постоянно мотаешься между отделами или часто работаешь из дома, ручное переключение VPN быстро начинает бесить. Ты берешь ноутбук, переходишь в другую зону, цепляешься к новому Wi-Fi — и туннель, естественно, отваливается. Приходится каждый раз лезть в клиент и переподключаться руками.

Хотелось получить простое решение: чтобы ноут сам понимал, где он сейчас находится — внутри доверенной корпоративной сети (где VPN не нужен) или снаружи, и автоматически поднимал туннель без моего участия.

Почему Планировщик задач, а не скрипт в фоне? Первая мысль при решении таких задач — написать скрипт с бесконечным циклом, закинуть его в фон, и пусть он проверяет сеть каждую минуту. Но это классический костыль. Постоянно крутящийся скрипт впустую ест ресурсы.

Правильнее ловить ивенты самой операционной системы. Когда Windows успешно подключается к любой сети (неважно, Wi-Fi это или патч-корд), служба NetworkProfile генерирует в системном журнале событие с ID 10000. Мы просто вешаем запуск нашего PowerShell-скрипта на этот триггер через Task Scheduler. В итоге скрипт спит и «дергается» только в момент реальной смены сети.

Как общаться с vpncli.exe У AnyConnect есть консольная утилита vpncli.exe. Сложность в том, что она интерактивная. При попытке подключения она начинает сыпать вопросами в консоль: просит подтвердить недоверенный сертификат, выбрать группу доступа, ввести логин и пароль.

Чтобы автоматизировать это, мы формируем в скрипте одну строку со всеми ответами по порядку, разделяя их переносом строки (символ `n). Затем просто скармливаем эту матрицу ответов утилите через конвейер, используя ключ -s для чтения стандартного ввода.

Безопасность: как не засветить пароль Хранить пароль от VPN в открытом текстовом файле или внутри самого скрипта нельзя. Заюзаем встроенный механизм Windows — DPAPI.

Мы один раз вводим пароль руками, скрипт превращает его в SecureString и сохраняет в файл. Фишка в том, что винда шифрует эту строку ключом вашей текущей учетной записи. Этот файл физически невозможно расшифровать, если скопировать его на другой комп или попытаться прочитать из-под другого пользователя. Основной скрипт будет на лету читать этот файл, расшифровывать пароль в оперативную память на долю секунды, передавать в AnyConnect и тут же затирать переменные. Само собой это тоже не супер защищенный момент но щито поделать-десу.

Пошаговая настройка и финальный скрипт

Шаг 1. Создаем файл с зашифрованным паролем Откройте PowerShell (с теми правами, под которыми вы работаете) и выполните эту команду. Она запросит пароль и сложит зашифрованный хеш в текстовик:

Тык
$cred = Read-Host -Prompt "Введите пароль от VPN" -AsSecureString
$cred | ConvertFrom-SecureString | Set-Content -Path "C:\Scripts\vpn_pass.txt" -Force

Шаг 2. Основной скрипт Создаём файл C:\Scripts\AutoVPN.ps1 и контрол-вэшним в него этот код. Главное не забыть вписать свои названия банковских сетей в массив $bankNetworks что бы исключить их их этого цирка.

Тык

# Массив имен доверенных сетей (SSID или домены)
$bankNetworks = @("Bank_WiFi_1", "Bank_WiFi_2", "Corp_LAN_Domain") 

$vpncli = "C:\Program Files (x86)\Cisco\Cisco AnyConnect Secure Mobility Client\vpncli.exe"
$vpnProfile = "11.22.33.44:1234"
$username = "username"
$encryptedPassPath = "C:\Scripts\vpn_pass.txt"

$currentNetworks = Get-NetConnectionProfile | Select-Object -ExpandProperty Name

$isBankNetwork = $false
foreach ($net in $currentNetworks) {
    if ($bankNetworks -contains $net) {
        $isBankNetwork = $true
        break
    }
}

# Если активно подключение к одной из сетей банка - прерываем выполнение
if ($isBankNetwork) {
    Exit
}


$vpnState = & $vpncli state

# Если туннель уже поднят - прерываем выполнение (защита от зацикливания)
if ($vpnState -match "state: Connected") {
    Exit
}

# Читаем файл как единую строку и отсекаем возможные невидимые символы
$encryptedString = (Get-Content $encryptedPassPath -Raw).Trim()

$secureString = ConvertTo-SecureString $encryptedString
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
$plainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) # Очистка памяти BSTR

$vpnInput = "y`n1`n$username`n$plainPassword"

# Передача матрицы в стандартный ввод vpncli
$vpnInput | & $vpncli -s connect $vpnProfile

$plainPassword = $null
$vpnInput = $null

Шаг 3. Настройка Планировщика задач (Task Scheduler)

Ну, тут все по классике, единственное что посоветую, делать delay на секунд 15 на случай если получение IP от маршрутизатора затянется.

В целом полезно. Спасибо за внимание!

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.