One of the most powerful features of Azure is it’s ability to seamlessly integrate with your on-premises environment, functioning similar to every other site.  To connect the Azure resources to the on-premises network, we use an Azure Gateway.

There are two types of gateways, and in the Classic Portal they’re known as Static Based Routing and Dynamic Based Routing.  The latter permits connections to Azure from multiple sites, however requires features that are not available in most routers.  As a result, connecting to a second site, such as Azure Resource Manager or a second physical location, becomes impossible.

Rather than purchase a router that will allow Dynamic Routing, or Route Based VPN as it’s known in the Azure RM Portal, we can connect the Azure Gateway to a Windows Server that is accessible to the Internet.  Our main requirement here is that the server needs 2 network adapters to route traffic between the Azure Site-to-Site VPN and the internal network.

To build the connection on-premises, we will need some information from the Azure Virtual Network Gateway, so let’s start there.  Since there’s not really any variations one can perform when building this configuration, I’m going to show you the entire process in PowerShell.  Just replace <StuffLikeThis> with what’s pertinent for your environment, such as changing <AzureGatewayIPAddress> to  I’ve also pre-populated some data, such as Azure Region and Subnet IP information.  Please customize to your requirements.

When working with Azure through PowerShell, I prefer to use the Integrated Scripting Environment instead of just PowerShell, if it’s going to be more than one line of code.  Visual Studio is also a great environment if you have access to it.  Let’s launch an Administrative ISE session and proceed…

First, we need to download the AzureRM PowerShell Module from Github ( and install it. Then, we need to connect into our Azure account and grab the subscription information.  With that, we will proceed to create a virtual network, gateway subnet, production subnet, and finally a public IP address for our Gateway.  Enter the following in the Script Pane


Select-AzureRmSubscription -SubscriptionName "&lt;AzureSubscriptionName&gt;"
New-AzureRmResourceGroup ProdRG1 -Location 'Canada Central'
$gwsubnet = New-AzureRmVirtualNetworkSubnetConfig -Name 'GatewaySubnet' -AddressPrefix
$subnet1 = New-AzureRmVirtualNetworkSubnetConfig -Name 'Subnet1' -AddressPrefix ''
New-AzureRmVirtualNetwork AzureNetwork -ResourceGroupName ProdRG1 -Location 'Canada Central' -AddressPrefix -Subnet $gwsubnet, $subnet2
New-AzureRmLocalNetworkGateway LocalSite -ResourceGroupName ProdRG1 -Location 'Canada Central' -GatewayIpAddress &lt;LocalSiteExternalIpAddress&gt; -AddressPrefix
New-AzureRmPublicIpAddress GwPublicIp -ResourceGroupName ProdRG1 -Location 'Canada Central' -AllocationMethod Dynamic

Now that we have the core networking configured, the next step is to create the actual gateway appliance.  Take note that if you changed the region or Resource Group name above, it will also need to be changed here.

$gwpublicip =Get-AzureRmPublicIpAddress GwPublicIp -ResourceGroupName ProdRG1
$vnet = Get-AzureRmVirtualNetwork AzureNetwork -ResourceGroupName ProdRG1
$gwsubnet = Get-AzureRmVirtualNetworkSubnetConfig GatewaySubnet -VirtualNetwork $vnet
$gwipconfig = New-AzureRmVirtualNetworkGatewayIpConfig GwIpConfig -SubnetId $ -PublicIpAddress $gwpublicip.Id
New-AzureRmVirtualNetworkGateway -Name AzureGateway1 -ResourceGroup ProdRG1 -Location 'Canada Central' -IpConfiguration $gwipconfig -GatewayType Vpn -VpnType RouteBased -GatewaySku Standard

Because I’m doing this in Hyper-V back on premises, I will connect a public (DMZ) internet connection to the 2nd NIC port on my host and create a new vSwitch for it.  I’m not going to tick off the box to share the vSwitch with the host OS, as I want that NIC and its public IP to go straight to my Azure Gateway VM.

With both vNICs attached to my VM and connecting to separate vSwitches, I’m going to go into the Network Control Panel and configure the following settings:

For the External Network:

  • IP Address
  • Subnet Mask
  • Default Gateway
  • DNS
  • In the advanced settings, under WINS, disable NetBIOS over TCP/IP

For the Internal Network:

  • IP Address
  • Subnet Mask
  • DNS
  • Leave Default Gateway blank

Next, we’re going to add the routing role to the VM.  Launch an administrative PowerShell session and type the following:

Install-WindowsFeature Routing, RemoteAccess, RSAT-RemoteAccess-PowerShell

#After the machine reboots. Launch PowerShell again to resume the configuration

Function Set-PrivateProfileString( 
  ## Prepare the parameter types and parameter values for the Invoke-WindowsApi script 
  $parameterTypes = [string], [string], [string], [string] 
  $parameters = [string] $category, [string] $key, [string] $value, [string] $file 
  ## Invoke the API 
  [void] (Invoke-WindowsApi "kernel32.dll" ([UInt32]) "WritePrivateProfileString" $parameterTypes $parameters)

</pre><div id="crayon-5aafd4f0a3a4c226809769-49" class="crayon-line"><span class="crayon-st">Function</span> <span class="crayon-r ">Set</span><span class="crayon-cn">-PrivateProfileString</span><span class="crayon-sy">(</span></div><div id="crayon-5aafd4f0a3a4c226809769-50" class="crayon-line crayon-striped-line"><span class="crayon-h">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="crayon-v">$file</span><span class="crayon-sy">,</span></div><div id="crayon-5aafd4f0a3a4c226809769-51" class="crayon-line"><span class="crayon-h">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="crayon-v">$category</span><span class="crayon-sy">,</span></div><div id="crayon-5aafd4f0a3a4c226809769-52" class="crayon-line crayon-striped-line"><span class="crayon-h">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="crayon-v">$key</span><span class="crayon-sy">,</span></div><div id="crayon-5aafd4f0a3a4c226809769-53" class="crayon-line"><span class="crayon-h">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="crayon-v">$value</span><span class="crayon-sy">)</span></div><div id="crayon-5aafd4f0a3a4c226809769-54" class="crayon-line crayon-striped-line"><span class="crayon-sy">{</span></div><div id="crayon-5aafd4f0a3a4c226809769-55" class="crayon-line"><span class="crayon-h">&nbsp;&nbsp;</span><span class="crayon-c">## Prepare the parameter types and parameter values for the Invoke-WindowsApi script </span></div><div id="crayon-5aafd4f0a3a4c226809769-56" class="crayon-line crayon-striped-line"><span class="crayon-h">&nbsp;&nbsp;</span><span class="crayon-v">$parameterTypes</span> <span class="crayon-o">=</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span><span class="crayon-sy">,</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span><span class="crayon-sy">,</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span><span class="crayon-sy">,</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span></div><div id="crayon-5aafd4f0a3a4c226809769-57" class="crayon-line"><span class="crayon-h">&nbsp;&nbsp;</span><span class="crayon-v">$parameters</span> <span class="crayon-o">=</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span> <span class="crayon-v">$category</span><span class="crayon-sy">,</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span> <span class="crayon-v">$key</span><span class="crayon-sy">,</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span> <span class="crayon-v">$value</span><span class="crayon-sy">,</span> <span class="crayon-sy">[</span><span class="crayon-t">string</span><span class="crayon-sy">]</span> <span class="crayon-v">$file</span></div><div id="crayon-5aafd4f0a3a4c226809769-58" class="crayon-line crayon-striped-line">&nbsp;</div><div id="crayon-5aafd4f0a3a4c226809769-59" class="crayon-line"><span class="crayon-h">&nbsp;&nbsp;</span><span class="crayon-c">## Invoke the API </span></div><div id="crayon-5aafd4f0a3a4c226809769-60" class="crayon-line crayon-striped-line"><span class="crayon-h">&nbsp;&nbsp;</span><span class="crayon-sy">[</span><span class="crayon-i">void</span><span class="crayon-sy">]</span> <span class="crayon-sy">(</span><span class="crayon-r ">Invoke-WindowsApi</span> <span class="crayon-s">"kernel32.dll"</span> <span class="crayon-sy">(</span><span class="crayon-sy">[</span><span class="crayon-i">UInt32</span><span class="crayon-sy">]</span><span class="crayon-sy">)</span> <span class="crayon-s">"WritePrivateProfileString"</span> <span class="crayon-v">$parameterTypes</span> <span class="crayon-v">$parameters</span><span class="crayon-sy">)</span></div><div id="crayon-5aafd4f0a3a4c226809769-61" class="crayon-line"><span class="crayon-sy">}</span></div><pre>
Install-RemoteAccess -VpnType VpnS2S
Add-VpnS2SInterface -Protocol IKEv2 -AuthenticationMethod PSKOnly -NumberOfTries 3 -ResponderAuthenticationMethod PSKOnly -Name AzureGateway -Destination &amp;lt;AzureGatewayIPAddress&amp;gt; -IPv4Subnet &amp;lt;AzureSubnet&amp;gt;/&amp;lt;CIDR&amp;gt; -SharedSecret &amp;lt;PreSharedKey&amp;gt;
Set-VpnServerIPsecConfiguration -EncryptionType MaximumEncryption
Set-VpnS2Sinterface -Name AzureGatetway -InitiateConfigPayload $false -Force
Set-PrivateProfileString $env:windir\System32\ras\router.pbk "&amp;lt;AzureGatewayIPAddress&amp;gt;" "IdleDisconnectSeconds" "0"
Set-PrivateProfileString $env:windir\System32\ras\router.pbk "&amp;lt;AzureGatewayIPAddress&amp;gt;" "RedialOnLinkFailure" "1"
Restart-Service RemoteAccess

This will install and configure the necessary components, including an IIS Web Server, configure the IPSec settings for the connection, and configure RemoteAccess to maintain the connection.  Finally, we type Connect-VpnS2SInterface to connect the gateway.

Within a couple of seconds, the tunnel will connect and Azure becomes a part of your network.  Now, any workloads deployed using the Virtual Network we created earlier will be accessible from on-premises users.

For more information on setting up the Site-to-Site VPN on the Azure side, please visit the Azure product team’s official document, located here.

Hope this helps!