Last active
February 6, 2022 02:51
-
-
Save bytespec/862c8f370d6018c76d6122ca423c16cf to your computer and use it in GitHub Desktop.
Example PowerShell code to create a system (all users) SSTP VPN. Use a .cmd file as a launcher within a .scapp file for an almost-one-click deploying via Screen Connect's Toolbox in Backstage mode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Settings | |
$VPN_NAME = "My System VPN" | |
$SERVER = "vpn.example.com:443" | |
$ROUTES = @("192.168.5.0/24", "192.168.6.0/24") # Empty to disable split tunneling | |
$USER = "sys-vpn-username" | |
# ======== | |
$ErrorActionPreference = "Stop" | |
# DLL stuff for setting credentials | |
Add-Type -Name "RAS" -Namespace "Win32" -MemberDefinition @' | |
public enum RasCredentialsMask { | |
RASCM_UserName = 0x00000001, | |
RASCM_Password = 0x00000002, | |
RASCM_DefaultCreds = 0x00000008 | |
} | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | |
public struct RASCREDENTIALS { | |
public Int32 dwSize; | |
public Int32 dwMask; | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] | |
public string szUsername; | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] | |
public string szPassword; | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] | |
public string szDomain; | |
} | |
[DllImport("rasapi32.dll", CharSet = CharSet.Ansi)] | |
public static extern int RasSetCredentialsA( | |
string PhoneBook, | |
string EntryName, | |
RASCREDENTIALS Credentials, | |
bool clearCredentials | |
); | |
'@ | |
$pbkPath = "$env:ProgramData\Microsoft\Network\Connections\Pbk\rasphone.pbk" | |
$host.UI.RawUI.WindowTitle = "$VPN_NAME Installer" | |
Write-Host "$VPN_NAME Installer" -ForegroundColor Cyan | |
Write-Host "" | |
$securePassword = Read-Host -Prompt "Enter VPN password for $USER (or blank to abort)" -AsSecureString | |
if ($securePassword.Length -eq 0) { | |
Write-Host "No password entered, installation aborted." -ForegroundColor Yellow | |
Write-Host "" | |
Write-Host "" | |
Read-Host -Prompt "Press RETURN to exit" | |
exit | |
} | |
$password = (New-Object System.Management.Automation.PSCredential "user", $securePassword).GetNetworkCredential().Password | |
Write-Host "" | |
Write-Host "Removing existing connection (if exists)... " -NoNewline | |
Get-VpnConnection -AllUserConnection -Name $VPN_NAME -ErrorAction SilentlyContinue | Remove-VpnConnection -AllUserConnection -Force | |
Write-Host "OK" -ForegroundColor Green | |
Write-Host "Creating new VPN... " -NoNewline | |
Add-VpnConnection -AllUserConnection -Name $VPN_NAME -ServerAddress $SERVER -TunnelType SSTP -EncryptionLevel Required -AuthenticationMethod MSCHAPV2 -RememberCredential | |
Write-Host "OK" -ForegroundColor Green | |
if ($ROUTES.Count -gt 0) { | |
Write-Host "Setting up split tunneling... " | |
Set-VpnConnection -AllUserConnection -Name $VPN_NAME -SplitTunneling $true | |
$ROUTES | ForEach-Object { | |
Write-Host " - $_... " -NoNewline; | |
Add-VpnConnectionRoute -AllUserConnection -ConnectionName $VPN_NAME -DestinationPrefix $_ | |
Write-Host "OK" -ForegroundColor Green | |
} | |
} | |
Write-Host "Setting VPN credentials... " -NoNewline | |
$creds = New-Object Win32.RAS+RASCREDENTIALS | |
$creds.dwSize = [System.Runtime.InteropServices.Marshal]::SizeOf($creds) | |
$creds.dwMask = [Win32.RAS+RasCredentialsMask]::RASCM_UserName -bor [Win32.RAS+RasCredentialsMask]::RASCM_Password -bor [Win32.RAS+RasCredentialsMask]::RASCM_DefaultCreds | |
$creds.szUsername = $USER | |
$creds.szPassword = $password | |
$result = [Win32.RAS]::RasSetCredentialsA($pbkPath, $VPN_NAME, $creds, $false) | |
if ($result -ne 0) { | |
throw ("Failed to set credentials, RasSetCredentialsA returned $result") | |
} | |
Write-Host "OK" -ForegroundColor Green | |
Write-Host "Configuring connection parameters..." -NoNewline | |
# PreviewUserPw = 0: to connect without interaction | |
# IpInterfaceMetric = 10: higher priority helps with DNS resolution | |
# IpDnsFlags = 1: to register IP with DNS after connecting | |
$processing = $false | |
(Get-Content -Path $pbkPath) | ForEach-Object { | |
if ($processing) { | |
Write-Output ( | |
$_ ` | |
-replace ("^PreviewUserPw=.*", "PreviewUserPw=0") ` | |
-replace ("^IpInterfaceMetric=.*", "IpInterfaceMetric=10") ` | |
-replace ("^IpDnsFlags=.*", "IpDnsFlags=1") | |
) | |
if ($_ -match "^\[") { | |
$processing = $false | |
} | |
} else { | |
Write-Output $_ | |
if ($_ -eq "[$VPN_NAME]") { | |
$processing = $true | |
} | |
} | |
} | Out-File -FilePath $pbkPath -Encoding ASCII | |
Write-Host "OK" -ForegroundColor Green | |
Write-Host "" | |
Write-Host "$VPN_NAME connection created." | |
while ($true) { | |
Write-Host ""; | |
Write-Host "Connect now? (Y/N): " -NoNewline -ForegroundColor Yellow | |
$response = (Read-Host).ToLower() | |
if ($response -eq "y") { | |
break | |
} elseif ($response -eq "n") { | |
Write-Host "" | |
Write-Host "Exiting without connecting." | |
Write-Host "" | |
Write-Host "" | |
Read-Host -Prompt "Press RETURN to exit" | |
exit | |
} | |
} | |
Write-Host "" | |
Write-Host "Attempting to connect... " -NoNewline; | |
$p = Start-Process -FilePath "rasphone.exe" -ArgumentList @("-d", "`"$VPN_NAME`"") -Wait -PassThru | |
if ($p.ExitCode -eq 0) { | |
Write-Host "OK" -ForegroundColor Green | |
} else { | |
Write-Host "Failed with code: $($p.ExitCode)" -ForegroundColor Red | |
} | |
Write-Host "" | |
Write-Host "Done!" | |
Write-Host "" | |
Write-Host "" | |
Read-Host -Prompt "Press RETURN to exit" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
`