Skip to content

Instantly share code, notes, and snippets.

@BercX
Created February 25, 2022 14:04
Show Gist options
  • Save BercX/2a201dac8015c28f66521f593b7e9b6f to your computer and use it in GitHub Desktop.
Save BercX/2a201dac8015c28f66521f593b7e9b6f to your computer and use it in GitHub Desktop.
l2tp_powershell_config

Info

Powershell script for creating an L2TP VPN connection with predefined settings. Script uses VPNCredentialsHelper module to set user and password.

################################################################################
# Server
$Name = 'work'
$Server = 'vpn.example.com'
$Network = '192.168.10.0/24'
# DNS
$DNSSuffix = 'corp.example.com'
# Auth
$PresharedKey = 'SECRET_PSK'
$User = 'USER'
$Password = 'SECRET_PASSWORD'
# Tunnel Settings
$TunnelType = 'L2tp' # Pptp, L2tp, Sstp, Ikev2, Automatic
$AuthenticationMethod = 'MSChapv2' # Pap, Chap, MSChapv2, Eap, MachineCertificate
$EncryptionLevel = 'Required' # NoEncryption, Optional, Required, Maximum, Custom
################################################################################
$ConnectionParams = @{
Name = $Name
ServerAddress = $Server
TunnelType = $TunnelType
AuthenticationMethod = $AuthenticationMethod
EncryptionLevel = $EncryptionLevel
Force = $true
RememberCredential = $true
SplitTunneling = $true
L2tpPsk = $PresharedKey
DnsSuffix = $DNSSuffix
}
Remove-VpnConnection -Name $Name -Force -ErrorAction SilentlyContinue
Add-VpnConnection @ConnectionParams
Add-VpnConnectionRoute -ConnectionName $Name -DestinationPrefix $Network
#region VPNCredentialsHelper
<#
Set-VpnConnectionUsernamePassword - by Paul Stancer.
Huge thanks to Jeff Winn for the DotRas project (https://dotras.codeplex.com/) which howed me the way,
and did all the really hard work.
https://github.com/paulstancer/VPNCredentialsHelper
#>
$code=@'
using System;
using System.Runtime.InteropServices;
public class VPNCredentialsHelper
{
private const int SUCCESS = 0;
private const int ERROR_ACCESS_DENIED = 5;
private const int UNLEN = 256;// Defines the maximum length of a username.
private const int PWLEN = 256;// Defines the maximum length of a password.
private const int DNLEN = 15;// Defines the maximum length of a domain name.
[Flags]
private enum RASCM
{
None = 0x0,
UserName = 0x1,
Password = 0x2,
Domain = 0x4
}
[DllImport("rasapi32.dll", CharSet = CharSet.Unicode)]
private static extern int RasGetErrorString(
int uErrorValue,
[In, Out] string lpszErrorString,
int cBufSize);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
private struct RASCREDENTIALS
{
public int size;
public RASCM options;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = UNLEN + 1)]
public string userName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = PWLEN + 1)]
public string password;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = DNLEN + 1)]
public string domain;
}
[DllImport("rasapi32.dll", CharSet = CharSet.Unicode)]
private static extern int RasSetCredentials(
string lpszPhonebook,
string lpszEntryName,
IntPtr lpCredentials,
[MarshalAs(UnmanagedType.Bool)] bool fClearCredentials);
public static bool SetCredentials(string entryName, string domain, string username, string password)
{
var credentials = new RASCREDENTIALS() { userName = username, password = password, domain = domain ?? string.Empty, options = RASCM.Domain | RASCM.UserName | RASCM.Password };
int size = Marshal.SizeOf(typeof(RASCREDENTIALS));
IntPtr pCredentials = IntPtr.Zero;
try
{
credentials.size = size;
pCredentials = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(credentials, pCredentials, true);
int ret = RasSetCredentials(null, entryName, pCredentials, false);
switch (ret)
{
case SUCCESS:
return true;
case ERROR_ACCESS_DENIED:
throw new UnauthorizedAccessException();
default:
throw ProcessRASException(ret);
}
}
finally
{
if (pCredentials != IntPtr.Zero)
{
Marshal.FreeHGlobal(pCredentials);
}
}
}
private static Exception ProcessRASException(int errorCode)
{
try
{
string buffer = new string('\x00', 512);
int ret = RasGetErrorString(errorCode, buffer, buffer.Length);
if (ret == SUCCESS)
return new RASException(errorCode, buffer.Substring(0, buffer.IndexOf('\x00')));
}
catch (EntryPointNotFoundException)
{
}
return new RASException(errorCode, "RAS Error code: " + errorCode.ToString());
}
public class RASException: Exception
{
public RASException(int errCode, string message):base(message)
{
RASErrorCode = errCode;
}
public int RASErrorCode { get; private set; }
}
}
'@
function Set-VpnConnectionUsernamePassword {
param
(
##[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True,HelpMessage='What connection name would you set the credentials?')]
[ValidateLength(3,255)]
[string]$connectionname,
##[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateLength(0,15)]
[string]$domain,
##[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateLength(0,255)]
[string]$username,
##[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateLength(0,255)]
[string]$password
)
Add-Type -TypeDefinition $code -IgnoreWarnings
Try
{
[VPNCredentialsHelper]::SetCredentials($connectionname, $domain, $username, $password)
}
Catch [System.UnauthorizedAccessException]
{
write-host "You do not have permissions to change the credentials" -ForegroundColor Red
}
Catch
{
write-host $_.Exception.Message -ForegroundColor Red
}
}
#endregion
Set-VpnConnectionUsernamePassword -connectionname $Name -username $User -password $Password -domain ''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment