Creating Azure Virtual Networks using Powershell and XML Part 4: Local networks and site-site connectivity

Posted by Rik Hepworth on Sunday, March 9, 2014

This is part 4 of a series of posts building powershell functions to create and modify Azure Virtual Networks. Previous posts have covered functions to create virtual networks and then delete them. In this part, I’m going to show you functions that will define local networks and configure site-site VPN connectivity between a local and virtual network.

Next on my list is to create functions to delete the local networks and remove the site-site connections. Then I really must look at functions to edit the configuration.

Adding the functionality for local networks also meant that I had to modify the get-azureNetworkConfig function to create the LocalNetworkSites xml node if it does not already exist, ready to hold our local network definitions.

The Functions

get-azureNetworkConfig

This is an update to the function shown in part 2.

function get-azureNetworkXml {
  $currentVNetConfig = get-AzureVNetConfig
  if ($currentVNetConfig -ne $null) {
    [xml]$workingVnetConfig = $currentVNetConfig.XMLConfiguration
  } else {
     $workingVnetConfig = new-object xml
  }
  $networkConfiguration = $workingVnetConfig.GetElementsByTagName("NetworkConfiguration")
  if ($networkConfiguration.count -eq 0) {
    $newNetworkConfiguration = create-newXmlNode -nodeName "NetworkConfiguration"
    $newNetworkConfiguration.SetAttribute("xmlns:xsd","http://www.w3.org/2001/XMLSchema")
    $newNetworkConfiguration.SetAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
    $networkConfiguration = $workingVnetConfig.AppendChild($newNetworkConfiguration)
  }
  $virtualNetworkConfiguration = $networkConfiguration.GetElementsByTagName("VirtualNetworkConfiguration")
  if ($virtualNetworkConfiguration.count -eq 0) {
    $newVirtualNetworkConfiguration = create-newXmlNode -nodeName "VirtualNetworkConfiguration"
    $virtualNetworkConfiguration = $networkConfiguration.AppendChild($newVirtualNetworkConfiguration)
  }
  $dns = $virtualNetworkConfiguration.GetElementsByTagName("Dns")
  if ($dns.count -eq 0) {
    $newDns = create-newXmlNode -nodeName "Dns"
    $dns = $virtualNetworkConfiguration.AppendChild($newDns)
  }
  $localNetworks = $virtualNetworkConfiguration.GetElementsByTagName("LocalNetworkSites")
  if ($localNetworks.count -eq 0) {
    $newlocalNetworks = create-newXmlNode -nodeName "LocalNetworkSites"
    $localNetworks = $virtualNetworkConfiguration.AppendChild($newLocalNetworks)
  }
  $virtualNetworkSites = $virtualNetworkConfiguration.GetElementsByTagName("VirtualNetworkSites")
  if ($virtualNetworkSites.count -eq 0) {
    $newVirtualNetworkSites = create-newXmlNode -nodeName "VirtualNetworkSites"
    $virtualNetworkSites = $virtualNetworkConfiguration.AppendChild($newVirtualNetworkSites)
  }
  return $workingVnetConfig
} 

add-azureVnetLocalNetworkSite

Add-azureVnetLocalNetworkSite takes three parameters: networkName is the name for the new local network; addressPrefix is the network prefix for the local network and vpnGatewayAddress is the ip address of the local VPN gateway that will establish the vpn tunnel. The function checks that the local network does not already exist and then creates the appropriate XML.

function add-azureVnetLocalNetworkSite {
  param (
    [string]$networkName,
    [string]$addressPrefix,
    [string]$vpnGatewayAddress
  )
  #check if the network already exists
  $siteExists = $workingVnetConfig.GetElementsByTagName("LocalNetworkSite") | where {$_.name -eq $networkName}
  if ($siteExists.Count -ne 0) {
    write-Output "Local Network Site $networkName already exists"
    $newNetwork = $null
    return $newNetwork
  }
  #get the parent node
  $workingNode = $workingVnetConfig.GetElementsByTagName("LocalNetworkSites")
  #add the new network node
  $newNetwork = create-newXmlNode -nodeName "LocalNetworkSite"
  $newNetwork.SetAttribute("name",$networkName)
  $network = $workingNode.appendchild($newNetwork)
  #add new address space node
  $newAddressSpace = create-newXmlNode -nodeName "AddressSpace"
  $AddressSpace = $network.appendchild($newAddressSpace)
  $newAddressPrefix = create-newXmlNode -nodeName "AddressPrefix"
  $newAddressPrefix.InnerText = $addressPrefix
  $AddressSpace.appendchild($newAddressPrefix)
  #add the new vpn gateway address
  $newVpnGateway = create-newXmlNode -nodeName "VPNGatewayAddress"
  $newVpnGateway.InnerText = $vpnGatewayAddress $network.AppendChild($newVpnGateway)
  #return our new network
  $newNetwork = $network
  return $newNetwork
}  

add-azureVnetSiteConnectivity

add-azureVnetSiteConnectivity takes two parameters: networkName is the name of the virtual network and localNetworkName is the name of the local network. It checks to make sure both are defined before creating the appropriate XML to define the connection. In order for the site-site VPN configuration to be applied, the virtual network must have a subnet named GatewaySubnet, so the function checks for that too. I already have a function to create subnets so I can use that to create the subnet. The function also currently specifies a type of IPSec for the connection as no other options are currently available for site-to-site vpn connections.

function add-azureVnetSiteConnectivity {
  param (
    [string]$networkName,
    [string\]$localNetworkName
  )
  #get our target network
  $workingNode = $workingVnetConfig.GetElementsByTagName("VirtualNetworkSite") | where {$_.name -eq $networkName}
  if ($workingNode.Count -eq 0) {
    write-Output "Network $networkName does not exist"
    $newVnetSiteConnectivity = $null
    return $newVnetSiteConnectivity
  }
  #check that the network has a GatewaySubnet
  $subNetExists = $workingNode.GetElementsByTagName("Subnet") | where {$_.name -eq "GatewaySubnet"}
  if ($subNetExists.count -eq 0) {
    write-Output "Virtual network $networkName has no Gateway subnet"
    $newVnetSiteConnectivity = $null
    return $newVnetSiteConnectivity
  }
  #check that the local network site exists
  $localNetworkSite = $workingVnetConfig.GetElementsByTagName("LocalNetworkSite") | where {$_.name -eq $localNetworkName}
  if ($localNetworkSite.count -eq 0) {
    write-Output "Local Network Site $localNetworkSite does not exist"
    $newVnetSiteConnectivity = $null
    return $newVnetSiteConnectivity
  }
  #check if the gateway node exists and if not, create
  $gateway = $workingNode.GetElementsByTagName("Gateway")
  if ($gateway.count -eq 0) {
    $newGateway = create-newXmlNode -nodeName "Gateway"
    $gateway = $workingNode.appendchild($newGateway)
  }
  #check if the ConnectionsToLocalNetwork node exists and if not, create
  $connections = $workingNode.GetElementsByTagName("ConnectionsToLocalNetwork")
  if ($connections.count -eq 0) {
    $newConnections = create-newXmlNode -nodeName "ConnectionsToLocalNetwork"
    $connections = $gateway.appendchild($newConnections)
  }
  #check to make sure our local site reference doesn't already exist
  $localSiteRefExists = $workingNode.GetElementsByTagName("LocalNetworkSiteRef") | where {$_.name -eq $localNetworkName}
  if ($localSiteRefExists.count -ne 0) {
    write-Output "Local Site Ref $localNetworkName already exists"
    $newVnetSiteConnectivity = $null
    return $newVnetSiteConnectivity
  }
  #add the local site ref
  $newVnetSiteConnectivity = create-newXmlNode -nodeName "LocalNetworkSiteRef"
  $newVnetSiteConnectivity.SetAttribute("name",$localNetworkName)
  $vNetSiteConnectivity = $connections.appendchild($newVnetSiteConnectivity)
  $newConnection = create-newXmlNode -nodeName "Connection"
  $newConnection.SetAttribute("type","IPsec")
  $vNetSiteConnectivity.appendchild($newConnection)
  #return our new subnet
  $newVnetSiteConnectivity = $vNetSiteConnectivity
  return $newVnetSiteConnectivity
} 

Using the functions

These functions modify an XML configuration that needs to be held in an object named $workingVnetConfig. Part 2 of this series showed how they can be loaded from a powershell file and called. Get-azureNetworkXml is required to get the XML configuration object. The functions here can then be used to remove items from that configuration, then save-azureNetworkXml will push the modified configuration back into Azure.