VPNCredentialsHelper.psm1
<#
Set-VpnConnectionUsernamePassword - by Paul Stancer. Huge thanks to Jeff Winn for the DotRas project (https://dotras.codeplex.com/) which showed me the way, and did all the really hard work. #> $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 } } export-modulemember -function Set-VpnConnectionUsernamePassword |