Простой скрипт добавления интерфейса IKEv2. Данное решение выполняет следующие задачи:
- Экспортирует сертификат пользователя и CA
- Добавляет интерфейс IKEv2
- Создает IPsec политику
- Связывает интерфейс с CA
- Отключает маршрут по умолчанию
- Отключает IPv6
- Отключает автометрику и выставляет метрику равной 1. Данная метрика не влияет на трафик, нужна только для смены порядка выбора DNS сервера (подробнее)
# powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0\add_ikev2.ps1"
# [Convert]::ToBase64String( [System.Text.Encoding]::Unicode.GetBytes( $(Get-Content "add_ikev2.ps1")))
# _________________________________________
param ($CreateBatch=$False)
$CurrentDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location -Path $CurrentDir
if ($CreateBatch -eq $true) {
$ps_file_name=(Get-Item $PSCommandPath).Name
$cmd_file_name=((Get-Item $PSCommandPath).Basename+".bat")
$encoded_script=[Convert]::ToBase64String( [System.Text.Encoding]::Unicode.GetBytes( $(Get-Content $ps_file_name -Raw)))
$content=("@echo off`r`n"+
"cd %~dp0`r`n"+
"powershell -Command [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('$encoded_script'))>$ps_file_name`r`n"+
"powershell -NoProfile -ExecutionPolicy Bypass -File $ps_file_name`r`n"+
"pause")
out-file -FilePath $CurrentDir\$cmd_file_name -InputObject $content -Encoding ASCII
exit
}
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if ( -Not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "Error! Run this script as administrtor" -ForegroundColor Red
exit
}
#############################
#
#############################
function TestPath ($Path) {
if (-not(Test-Path -Path $Path -PathType Leaf)) {
Write-Host "Error! $Path not found" -ForegroundColor Red
exit
}
}
function CheckFailExit ([bool]$State,[string]$TextMessage,[string]$CommandForError){
if ($State){
Write-Host "Error! $TextMessage with error!" -ForegroundColor Red
if ($CommandForError.Length -gt 0 ){
Invoke-Expression -Command $CommandForError
}
exit
} else {
Write-Host "$TextMessage succesfully"
}
}
#############################
#
#############################
$IniFile="settings.ini"
TestPath -Path $IniFile
$arrSettings=$(Get-Content $IniFile | ConvertFrom-StringData)
$FileCA="$CurrentDir\"+$arrSettings.FileCA
$FileP12="$CurrentDir\"+$arrSettings.FileP12
$ConnectionName=$arrSettings.ConnectionName
$ServerAddress=$arrSettings.ServerAddress
$ErrorActionPreference = "SilentlyContinue"; #This will hide errors
TestPath -Path $FileCA
TestPath -Path $FileP12
$PSK = Get-Credential -UserName 'Enter password below' -Message 'Enter password below'
Import-PfxCertificate -FilePath $FileP12 -CertStoreLocation 'Cert:\LocalMachine\My' -Password $PSK.Password | out-null
CheckFailExit -State $(!$?) -TextMessage "Import user`s cert finish"
Import-Certificate -FilePath $FileCA -CertStoreLocation cert:\LocalMachine\Root | out-null
CheckFailExit -State $(!$?) -TextMessage "Import CA cert finish"
Add-VpnConnection -ConnectionName "$ConnectionName" -ServerAddress "$ServerAddress" -TunnelType 'Ikev2' -AuthenticationMethod MachineCertificate -EncryptionLevel "Maximum" | out-null
CheckFailExit -State $(!$?) -TextMessage "Add VPN connection finish"
Set-VpnConnectionIPsecConfiguration -ConnectionName "$ConnectionName" -AuthenticationTransformConstants SHA196 -CipherTransformConstants AES256 -EncryptionMethod AES256 -IntegrityCheckMethod SHA1 -PfsGroup None -DHGroup Group14 -PassThru -Force | out-null
CheckFailExit -State $(!$?) -TextMessage "Set IPSec param for VPN connection finish" -CommandForError "Remove-VpnConnection -ConnectionName ""$ConnectionName"""
Set-VpnConnection -ConnectionName "$ConnectionName" -MachineCertificateIssuerFilter "$FileCA" -SplitTunneling $True | out-null
CheckFailExit -State $(!$?) -TextMessage "Set CA for VPN connection finish"
# BLOCK to change extented interface settings BEGIN
# Function converts ini files to HashTable (pbk recursion)
function Get-IniContent ($filePath)
{
$ini = [System.Collections.Generic.Dictionary[string,psobject]]::new([StringComparer]::OrdinalIgnoreCase)
switch -regex -file $FilePath
{
"^\[(.+)\]" # Section
{
$section = $matches[1]
$ini[$section] = [System.Collections.Generic.Dictionary[string,psobject]]::new([StringComparer]::Ordinal)
$CommentCount = 0
}
"^(;.*)$" # Comment
{
$value = $matches[1]
$CommentCount = $CommentCount + 1
$name = “Comment” + $CommentCount
$ini[$section][$name] = $value
}
"(.+?)\s*=(.*)" # Key
{
$name,$value = $matches[1..2]
$ini[$section][$name] = $value
}
}
return $ini
}
# The function converts the HashTable obtained by the Get-IniContent function into an ini file (pbk)
function IniContentToString ($iniContent){
$iniString=""
foreach ($section in $iniContent.Keys){
$iniString=$iniString+"`r`n"+"["+$section+"]"
foreach ($Name in $iniContent[$section].Keys){
$StrIni=$($Name + "=" +$iniContent[$section][$Name])
$iniString=$iniString+"`r`n"+$StrIni
}
}
return $iniString
}
$rasphone="$env:USERPROFILE\AppData\Roaming\Microsoft\Network\Connections\Pbk\rasphone.pbk"
$iniContent = Get-IniContent $rasphone
$iniContent["$ConnectionName"].IpInterfaceMetric=1
$iniContent["$ConnectionName"].ExcludedProtocols=8
$iniContent["$ConnectionName"].PreferredHwFlow=1
$iniContent["$ConnectionName"].PreferredProtocol=1
$iniContent["$ConnectionName"].PreferredCompression=1
$iniContent["$ConnectionName"].PreferredSpeaker=1
$iniContent["$ConnectionName"].AutoTiggerCapable=0
$iniContent["$ConnectionName"].Ipv6PrioritizeRemote=1
$iniString=IniContentToString $iniContent
out-file -FilePath $rasphone -InputObject $iniString -Encoding ASCII
CheckFailExit -State $(!$?) -TextMessage "Change interface settings"
# BLOCK change extented settings interface END
Write-Host "Congragulation! VPN interface create successfully!" -ForegroundColor Green
$ErrorActionPreference = "Continue"; #Turning errors back on
Настройки берутся из файла settings.ini, который должен лежать в этом же каталоге. Файл имеет следующий синтаксис:
FileP12=crt\\user.p12
FileCA=crt\\ca.crt
ConnectionName=Roga_IKEv2
ServerAddress=vpn.roga.com
Косая черта обязательно дожна экранироваться.
Стандартный функционал cmd/PoSh не позволяет менять два последних пункта первого списка. Данный результат достигается при помощи редактирования файла rasphone.pbk. На просторах интернета предлагается регуляркой заменить все вхождения на нужные, но нас такой вариант не устраивает, так как у конечного пользователя может быть куча других VPN интерфейсов. Я обратил внимание на синтаксис файла, и технически это тот же Ini файл, к которому я применил доработанный скрипт конвертации Ini в HashTable, где секция (она же интерфейс) выступает в качестве первого уровня. Вот тут и выяснилось, что по умолчанию словарь РегистроНезависисмый
# Регистрозависимый словарь
[System.Collections.Generic.Dictionary[string,psobject]]::new([StringComparer]::Ordinal)
# РегистроНЕзависимый словарь
[System.Collections.Generic.Dictionary[string,psobject]]::new([StringComparer]::OrdinalIgnoreCase)
# или
@{}
Еще интересный момент - как это ни странно ASCII сохраняет в UTF-8 w/o BOM
out-file -FilePath $Path -InputObject $Content -Encoding ASCII
End of string в стиле Windows при сборе контента можно достичь указанием перевода строки и каретки "`r`n"
Т.о. мы можем обратиться к параметрам именно нужного нам интерфейса. После корректировки параметров, выявленных эмпирическим путем, таблица моей функцией разматывается обратно в Ini файл и сохраняется на прежнее место.
Комментариев нет:
Отправить комментарий