Deploying a Windows 10 VPN Profile from Intune for Azure VPN Gateway Basic Sku


Azure VPN Gateway Basic Sku.. The poor man’s P2S VPN solution. Or is it?

If you check the notes on the Azure VPN Basic Sku P2S solution:
P2S_01
This table is taken from https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpngateways and it shows the limitations of the Basic Sku. The table goes on and on, but I just wanted to show the Basic Sku’s properties. Specifically the P2S options. SSTP only, 128 (simultaneous) connections. More than enough for small businesses. Or home labs. BGP not supported, which means you need to take care of routing tables yourself. A maximum of 10 S2S tunnels, which means you can connect 10 sites to the Virtual Network holding the VPN Gateway deployment. Again, more than enough for small businesses. Or home Labs.

Looking at pricing:
P2S_02
This table is taken from https://azure.microsoft.com/en-us/pricing/details/vpn-gateway/ and it shows pricing in Euros for West Europe. Basic Sku is by far the cheapest solution.

In short, Basic Sku seems like the perfect solution for small businesses and especially for home Labs.

The only thing I don’t like about the Basic Sku is the P2S Client options you get out of the box when you deploy the solution. The out of the box solution and how to get there is not in scope of this post. You can find more info and instructions in some of my other posts:
https://msfreaks.wordpress.com/2015/12/07/building-an-azure-lab-implementing-p2s-point-to-site-vpn/ (Classic, but shows the basic implementation).
https://msfreaks.wordpress.com/2015/12/11/building-an-azure-lab-customizing-the-p2s-point-to-site-vpn-client/
https://msfreaks.wordpress.com/2015/12/03/building-an-azure-lab-implementing-s2s-site-to-site-vpn/
https://msfreaks.wordpress.com/2017/11/28/building-an-azure-lab-implementing-s2s-site-to-site-vpn-using-azure-portal-or-powershell/
https://msfreaks.wordpress.com/2017/12/02/building-an-azure-lab-implementing-s2s-site-to-site-vpn-part-2-multi-virtual-networks/

So I started some research on how to effectively deploy and manage the VPN client (on Windows 10) when using the Azure VPN Gateway Basic Sku.

For reference, this is the setup for my VPN infrastructure, showing the managed Windows 10 client on which I want to deploy the P2S VPN connection:
P2S_23

First, let’s have a look at why I don’t like the out of the box VPN client options.
P2S_03
You can download your VPN client package in the Point-to-site configuration blade for your VPN Gateway. I specifically say “your” because this package is tailored for this VPN Gateway, and this VPN Gateway only. That is why it takes a little while before your download starts.
The download is a zip file, which once extracted, shows 3 client options:
P2S_04
A “Generic” “Client”, a x64 client package, and a x86 client package. The Generic client simply shows an xml file and the Gateway certificate. Examine the xml file, it will tell you all sort of configuration stuff for the VPN Client:
P2S_05
From this we can get the actual VPN Gateway address, the type, which is SSTP, the routes that are needed, and the authentication method that is needed.

Creating a PKI, and getting the right certificates installed is out of scope of this post.

Let’s check the obvious choice, the x64 client package.
Installing the package in the user context:
P2S_06
Oops. Unsigned, meaning crappy user experience. Ignoring that for now, click “More info” and click “Run anyway”.
P2S_07
Oops. Need elevated administrator access to install this.
Let’s see if it installs machine-wide using an administrator account. Logging on with an administrator and running the same setup again:
P2S_08
So no pesky SmartScreen popup for administrators.
P2S_09
VPN Connection available.
Now logging back in with the normal user, without administrative permissions:
P2S_10
No VPN Connection. So the installation of the VPN Client package is not a machine-wide installer, when using an administrative account. It shows up for the administrator I am logged on with, so it will also not show up for a normal user. Spoiler-alert: even running it as System, using psexec, it will not install machine-wide.

So how to install the connection in the user context, or how to install the connection machine wide, and of course, I want it to be unattended.

Looking around my favorite wiki (google.com) to look for solutions other people have come up with, I found this excellent article which got me started: https://www.risual.com/2018/07/05/manually-configure-azure-point-to-site-on-windows-10/.
I have two issues with this solution though.
First one is a pesky (one-time) certificate warning.
P2S_11
For which a workaround could probably be found. It’s a one-time thing, it has to be registered somewhere right? But the second problem with this solution, and one that prevented me from trying to figure out how to get rid of the first one, is that you need to add routes to tell your machine where to route packets if they are meant to go to the Azure Virtual Network using the VPN Gateway.
A normal user does not have enough rights to do this, and besides, I don’t want them to be static. Like a proper VPN Connection, routes should be added as needed when the connection is established and they need to be removed when the connection is ended or disconnected.

Thank you Risual, close, but no cigar.

So what other options are left? Well, Windows 10 has a native VPN provider (the same one that is used in the article from Risual), and it can be configured using xml VPNv2 profiles.

More information on VPNv2 xml profiles can be found here: https://docs.microsoft.com/en-us/windows/client-management/mdm/vpnv2-csp.

Cool thing about these profiles is that they can be used for deployment using Intune.

Let’s dig into configuring that. I will show you how to capture a VPNv2 xml for deployment in Intune.

First make sure that the Root certificate from the Point-to-site configuration on the VPN Gateway is also a Trusted Root certificate on the machine on which you configure the next steps. Also make sure you have a client certificate that matches that Root certificate in the certificate path. Again, doing so, and configuring those certificates, is outside of the scope of this post.
Those certificates not required to capture the VPN profile which I am about to show you, but they are required if you also want to test the profile before capturing it.

In the Start Menu, type “VPN”.
P2S_12
Click “Add a VPN connection”.
P2S_13
Click “Add a VPN connection”.
P2S_14
Choose “Windows (built-in)” as VPN provider. I entered my Azure VPN Gateway name as the Connection Name. For Server name or address provide the address that you can get from the xml in the “Generic Client” folder. VPN type should be Automatic, because SSTP type is not (yet) supported, Type of sign-in info should be Certificate. I also left the Remember my sign-in info check enabled.
Click Save.
P2S_15
Now click Change adapter options and open the properties for the newly created adapter.
P2S_16
On the Security tab, switch Data encryption to “Require encryption” and then click Properties.
P2S_17
Uncheck Verify the server’s identity (gets rid of the certificate warning which remained in the Risual article).

Click OK three times and test the connection (Remembering that testing only works if you have the Root certificate and a valid user certificate installed on the machine you are using to capture the VPN profile):
P2S_19
Success! At least for the first part. The routes are still not there. And it’s a manual nightmare. Fret not, we will get there. We will use this VPN connection to build our own VPNv2 xml profile.

Time to grab the xml from the profile we just created.

Run the following PowerShell code (after replacing my values with your own values for the variables $Name, $Server, $DnsSuffix, $OutputFile, and $RouteConfig before running it):

$Name = "ITW-01"
$Server = "azuregateway-e4850069-xxxx-xxxx-xxxx-ae72007d9e79-585c3b92babd.vpn.azure.com"
$DnsSuffix = "it-worxx.local"
$OutputFile = "$($env:TEMP)\VPNv2_Profile.xml"
$RouteConfig = @("<Route><Address>192.168.2.0</Address><PrefixSize>24</PrefixSize></Route>
<Route><Address>10.161.253.0</Address><PrefixSize>24</PrefixSize></Route>
<Route><Address>10.162.253.0</Address><PrefixSize>24</PrefixSize></Route>
<Route><Address>10.163.253.0</Address><PrefixSize>24</PrefixSize></Route>
<Route><Address>10.164.253.0</Address><PrefixSize>24</PrefixSize></Route>")

@("<VPNProfile>
  <ProfileName>$($Name.ToLower())profile</ProfileName>
  <!-- the dns suffix to use for the vpn adapter -->
  <DnsSuffix>$($DnsSuffix)</DnsSuffix>
  <NativeProfile>
    <!-- the azure vpn gateway address goes here -->
    <Servers>$Server</Servers>
    <!-- for azure vpn gateway basic sku this must be Automatic -->
    <NativeProtocolType>Automatic</NativeProtocolType>
    <Authentication>
      <!-- this must be eap and a valid eap configuration must be supplied -->
      <UserMethod>Eap</UserMethod>
      <Eap>
        <Configuration>
          <!-- sabm eap configuration taken from template profile -->
          $((Get-VpnConnection -Name $Name).EapConfigXmlStream.InnerXml)
        </Configuration>
      </Eap>
    </Authentication>
    <!-- activate splittunnel configuration -->
    <RoutingPolicyType>SplitTunnel</RoutingPolicyType>
    <!-- disable class based default route -->
    <DisableClassBasedDefaultRoute>true</DisableClassBasedDefaultRoute>
  </NativeProfile>
  <RememberCredentials>true</RememberCredentials>
  <!-- add route config for this connection -->
  $RouteConfig
</VPNProfile>") | Out-File -FilePath $OutputFile

The result will be an xml file in your output destination, which, you guessed right, is the VPNv2 xml profile. Mine looks like this when I run the script:

<VPNProfile>
  <ProfileName>it-worxxprofile</ProfileName>
  <!-- the dns suffix to use for the vpn adapter -->
  <DnsSuffix>it-worxx.local</DnsSuffix>
  <NativeProfile>
    <!-- the azure vpn gateway address goes here -->
    <Servers>azuregateway-e4850069-xxxx-xxxx-xxxx-ae72007d9e79-585c3b92babd.vpn.azure.com</Servers>
    <!-- for azurre vpn gateway basic sku this must be Automatic -->
    <NativeProtocolType>Automatic</NativeProtocolType>
    <Authentication>
      <!-- this must be eap and a valid eap configuration must be supplied -->
      <UserMethod>Eap</UserMethod>
      <Eap>
        <Configuration>
          <!-- sabm eap configuration taken from template profile -->
          <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig"><EapMethod><Type xmlns="http://www.microsoft.com/provisioning/EapCommon">13</Type><VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId><VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType><AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId></EapMethod><Config xmlns="http://www.microsoft.com/provisioning/EapHostConfig"><Eap xmlns="http://www.microsoft.com/provisioning/BaseEapConnectionPropertiesV1"><Type>13</Type><EapType xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV1"><CredentialsSource><CertificateStore><SimpleCertSelection>true</SimpleCertSelection></CertificateStore></CredentialsSource><ServerValidation><DisableUserPromptForServerValidation>false</DisableUserPromptForServerValidation><ServerNames></ServerNames></ServerValidation><DifferentUsername>false</DifferentUsername><PerformServerValidation xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV2">false</PerformServerValidation><AcceptServerName xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV2">false</AcceptServerName><TLSExtensions xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV2"><FilteringInfo xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV3"><CAHashList><IssuerHash>8c ff ff ff ff b3 c9 20 3f c1 b1 da 3f 02 77 b5 93 fd 3b 3e </IssuerHash></CAHashList></FilteringInfo></TLSExtensions></EapType></Eap></Config></EapHostConfig>
        </Configuration>
      </Eap>
    </Authentication>
    <!-- activate splittunnel configuration -->
    <RoutingPolicyType>SplitTunnel</RoutingPolicyType>
    <!-- disable class based default route -->
    <DisableClassBasedDefaultRoute>true</DisableClassBasedDefaultRoute>
  </NativeProfile>
  <RememberCredentials>true</RememberCredentials>
  <!-- add route config for this connection -->
  <Route><Address>192.168.2.0</Address><PrefixSize>24</PrefixSize></Route>
  <Route><Address>10.161.253.0</Address><PrefixSize>24</PrefixSize></Route>
  <Route><Address>10.162.253.0</Address><PrefixSize>24</PrefixSize></Route>
  <Route><Address>10.163.253.0</Address><PrefixSize>24</PrefixSize></Route>
  <Route><Address>10.164.253.0</Address><PrefixSize>24</PrefixSize></Route>
</VPNProfile>

And this is the profile data we can use to publish the profile using Intune.

In Intune, create a new Configuration Profile.
P2S_20
Give it a name, select Windows 10 and later for Platform, and most importantly, select Custom Profile Type.

In the Custom OMA-URI settings tab click Add.
P2S_21
Name and Description really don’t matter. What’s important here is the OMA-URI. This should be like “./user/vendor/MSFT/VPNv2/<profile name>/ProfileXML” where “<profile name>” will be the name for the VPN connection once it’s deployed and visible in Windows 10. In my case I entered “./user/vendor/MSFT/VPNv2/IT-WorXX/ProfileXML” as the OMA-URI. Also note here that this profile name setting does not have to match the profile name that you used to capture the VPNv2 profile.
The Data type must be string, and in the Value field you paste the captured profile xml.

When you’re done don’t forget to assign the profile. I chose to assign it to All users.

Time to test the setup.
P2S_22
When I log on to a managed device with a user that has the VPN profile assigned, it shows up in the available connections.
P2S_24
In the above screenshot you can see the initial IP Config output, and the IP Config output with the “IT-WorXX” VPN connection in a connected state.
P2S_25
The initial IPv4 Route Table, which clearly shows there’re no routes to the address spaces in Azure, and no routes to my on-premises networks.
P2S_26
And after connecting the “IT-WorXX” VPN Connection, the IPv4 Routing Table show routes to the Azure address spaces, and the on-premises network.

There’s one more “gotcha” with this setup.

I have configured custom DNS servers on the Azure Virtual Network. What happens here is when I connect the “IT-WorXX” VPN profile, I automatically receive these DNS servers on the VPN client connection:
P2S_28
If for some reason your configuration prevents you from entering custom DNS servers your client will receive no DNS server settings when it is connected.
You can solve this issue by modifying the XML file for the VPNv2 profile between the DnsSuffix and NativeProfile tags:

<VPNProfile>
  <ProfileName>it-worxxprofile</ProfileName> 
  <!-- the dns suffix to use for the vpn adapter -->
  <DnsSuffix>it-worxx.local</DnsSuffix>
  <DomainNameInformation>
    <DomainName>.it-worxx.local</DomainName>
    <DnsServers>10.161.253.4,192.168.2.4</DnsServers>
  </DomainNameInformation>
  <NativeProfile>

And that’s it. A fully managed VPNv2 profile deployment using Intune, which allows you to connect to an Azure VPN Gateway Basic Sku P2S configuration.

Until next time,

Arjan

25+ years experience in Microsoft powered environments. Enjoy automating stuff using powershell. In my free time (hah! as if there is any) I used to hunt achievements and gamerscore on anything Xbox Live enabled (Windows Mobile, Windows 8, Windows 10, Xbox 360 and Xbox One). Recently I picked up my Lego addiction again.

Tagged with: , , , , ,
Posted in Automation, Azure, Powershell, Step-by-Step guide, Virtual Networking
19 comments on “Deploying a Windows 10 VPN Profile from Intune for Azure VPN Gateway Basic Sku
  1. Avaron says:

    I don’t get an .xml as in your example when I run the script. Any guidance on what I missed?

    • Arjan Mensch says:

      Hi Avaron,
      Did you change the output? $OutputFile = “$($env:TEMP)\VPNv2_Profile.xml”
      If not, it should be in the TEMP folder for the useraccount you used to run the script.

      • Avaron says:

        We did update the file path and we do generate an output file. However, all it contains is the VPN Name we specify and the DNS we specify

      • Arjan Mensch says:

        Can you send me the PS script you executed?

      • Avaron says:

        Trying a different text editor we were able to get the .xml output as described in your example. Followed the other steps and we are able to get the VPN deployed. Next road block… when we try to connect using the profile that was pushed by Intune, first error we face is the server address isn’t populated and it needs to be manually added. When that is done we get a second error where we are challenged for a user name and password. To our understanding this shouldn’t be because we’re authenticating using certificates.

      • Arjan Mensch says:

        Cert auth only works if the cert authority cert is on the gateway’s p2s settings and on the endpoints as well. Was your gateway redeployed? It will get a different name then. Orher than that, check your script for weird quotes, which sometimes happens when copying code from wordpress sites.

      • Avaron says:

        Thanks again for the assistance. On the device the vpn profile was deployed to, we found that the issue appears to be that the profile that is set by Intune is missing necessary settings. Once the profile is deployed, and we must manually supply the server address. We must then manually change authentication to EAP and select certificate auth, and then manually remove the option to validate the certificate. We must also manually add our domain suffix. Once all these manual changes are made, the profile does work. We are just trying to understand why the profile is lacking these settings initially. They were configured on the profile that was sampled by the original powershell script.

    • Mat says:

      Hello, Thank you for your post it is amazingly well documented. I managed to go throughts all the steps. Unfortunatelly the profile in INTUNE is stuck to ‘PENDING’. I have tried to apply it to other computers/user : same it does not work.
      If I take a INTUNE template then it works…
      Any thoughts ?
      Mat

  2. jonscriven says:

    Thanks for this helpful article. In the Powershell to create the XML file you seem to define a variable $DnsSuffix but then don’t use it in the creation of the file. (you have a hardcoded Suffix). I can have a guess at the syntax but you might want to correct it on your post?

  3. jonscriven says:

    Posted already about this several times, but post won’t seem to stick! Maybe I need to strip out the Powershell and XML – will try that. Can send that detail if you tell me how.

    I created an XML file using your post, but the one I created doesn’t appear to have included any certificate information within it. (Detail appended)

    The XML file included in the Azure Portal VPN Client download does have a tag but this does not seem to have been included in the output XML.

    This was the exact Powershell I ran (all information sanitised):-

    XML File downloaded from Azure Portal – VPNSettings.xml:-

    XML File created by the script – VPNv2_Profile.xml:-

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog Authors
https://paypal.me/ArjanMensch
BTC:1AiAL6QDbfNPiduYYEoy3iNS2m6UKJW2He

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 434 other followers

Blog Stats
  • 3,276,454 hits
  • An error has occurred; the feed is probably down. Try again later.
  • An error has occurred; the feed is probably down. Try again later.
%d bloggers like this: