Author Archives: hmmconfused

UPDATED: Managing Azure Network Security Groups using CSV files

As with all scripts they need some maintenance over time and this one was no exception.

There were two bugs found in the script:

  1. The port ranges weren’t going all the way to 65535 so that has been resolved now.
  2. When creating a new NSG in Azure Resource Manager the location validation was failing. This has now been fixed. The location can be passed as the Display Name, for example ‘West Europe’ or as the ARM internal name ‘westeurope’ – either will work and they are validated against the Get-AzureRmLocation cmdlet.

The updated script can be downloaded from TechNet Gallery


App Requirement Gathering for Azure RemoteApp

Having just done a PoC on Azure RemoteApp I thought it would be useful to create a template document to supply to customers so they can gather some application requirements before deploying RemoteApp.

The document can be downloaded here.

Please feel free to make some comments below if you can think of improvements!

EDIT: Link now working, apologies for that!

App Gathering Requirements

App Gathering Requirements

Azure RemoteApp with Remote Data

Azure RemoteApp allows you to run Line of Business (LOB) applications from Remote Desktop Session (RDS) hosts being run from Azure. The RDS hosts only offer RemoteApp – where the application that the user is running is shown on the user’s device – it does not offer Remote Desktops for users.

This week I’ve been doing a RemoteApp PoC for an international media company where the data they require users to access are located in datacenters all over the world. Currently the organization doesn’t have Azure ExpressRoute deployed and they have Firewall devices that only support Static VPN Gateways in Azure so connectivity is limited.

RemoteApp PoC
The diagram below shows the configuration of the RemoteApp PoC:

RemoteApp PoC

RemoteApp PoC Diagram

The VPN was configured to only allow access to the subnets available in the datacenter the VPN was connected to, although the datacenter was connected to others via separate WAN links.

The data required for the RemoteApp applications is located in the on premises datacenters. This lead to some problems as it was discoverd the applications needed data from two datacenter locations. The internal network team updated the datacenter routing and after some communication with the development team (and local IT administrators) the application documentation was updated to reflect the application touch points. After this the application required some changes to ACLs on folders in gold image to function correctly.

What if ExpressRoute was available?
The customer is looking to deploy ExpressRoute to get around these problems. How would it help?

Deploying a MPLS based ExpressRoute, and having it connected to all of the customer’s datacenters, would have allowed the Virtual Network in Azure to access all of the application touch points. This could be achieved with multiple VPN connections however their firewalls do not support Dynamic Routing.

RemoteApp With ER

RemoteApp With ER

Get your Apps Documented
To make deployment of Azure RemoteApp easier it is crucial to have the applications that you want to use documented. If you don’t have the applications documented I would suggest using the Sysinternals tools to monitor what the application is trying to connect to. Process Explorer and TCPView would be of benefit here.

Azure Pack Websites Offline Installation Package Creator

I’ve been working a customer recently who, through no fault of their own, is not on the latest update rollup of Windows Azure Pack. They are currently running UR4. Unfortunately I don’t have an offline copy of WAP Websites UR4 to give the customer… To avoid this issue in the future I have created a PowerShell script that creates an offline installation package for me.

It requires having the WAP Websites installation on the machine where the script is be run from. It will create a ZIP file containing all of the required components for an offline installation.

The script can be downloaded here.

WAP Download Script for Offline Installation

This is a simple script that downloads the WAP components that are available through the WebPI so they can be used to peform an offline installation. It requires the Web Platform Installer to be installed (

It downloads anything that has “Azure Pack” in title, so it will pick up items such GridPro Resource Management, Cloud Cruiser, etc.

As well as giving the ability for an offline installation it can be useful it you wish to add to your existing WAP installation at a later date but are not running the latest version.

The script can be downloaded from here.

UPDATED: Managing Azure Network Security Groups using CSV files

UPDATE 18th August 2015: The script has been updated to significantly reduce the time it takes to validate the port ranges. The updated script is available on TechNet Gallery using the same URL.

Azure Network Security Groups allow you to apply Access Control Lists to VMs and Virtual Subnets (not an entire Virtual Network in one hit) in Microsoft Azure. More details on what an Azure Network Security Group is can be found here:

Recently I’ve been working with a customer who wants to move a LOT of their Virtual Machine infrastructure to Azure and will be reliant upon Azure Network Security Groups to apply security to VMs and Virtual Subnets. They needed an easy way to manage all of these in Azure as they will have many different Azure Accounts and Subscriptions – mainly due to the Azure subscription limitations (Azure Limitations) as they will have a LOT of their services in Azure.

To allow them to manage their Azure Network Security Groups I created a PowerShell script which reads a CSV file that contains Azure Network Security Group Rules and creates it in Azure. In addition it can update an already created Azure Network Security Group with new rules, update existing and remove existing as required.

The screenshot below shows an example Azure Network Security Group CSV file:


The script has two main functions:

  1. New-CustomAzureNetworkSecurityGroup
  2. Update-CustomAzureNetworkSecurityGroup

Here is example of how to invoke each:

  1. New-CustomAzureNetworkSecurityGroup -CSVPath C:\AzureNetworkSecuriyGroupRules\VS-DMZ-NSG.csv -NetworkSecurityGroupName "VS-DMZ-NSG" -AzureLocation "North Europe" -NetworkSecurityGroupLabel "This contains the rules for the Virtual Subnet VS-DMZ"
  2. Update-AzureCustomNetworkSecurityGroup -CSVPath C:\AzureNetworkSecuriyGroupRules\VS-DMZ-NSG.csv -NetworkSecurityGroupName "VS-DMZ-NSG"

The first thing the script does is validate each rule against Microsoft’s criteria (which can be found here About Azure Network Security Groups). If this is passed then it will move to either creating or updating the required Azure Network Security Group as has been instructed.

When the Script updates the rules in the Azure Network Security Group it processes them based on the priority value defined in the CSV, inbound first then outbound rules. If there is a clash in priority numbers between a new/updated rule and a rule that already exists in the Azure Network Security Group (that may be being updated further down the list of rules or removed entirely) it will decrement the Priority value temporarily. After this the Script will remove any rules missing from the CSV file so the Azure Network Security Group matches the CSV file. Once this is complete the Script will attempt to assign rules their correct priority value.

This script will NOT apply the Azure Network Security Group to a VM or a Subnet; is just creates the Azure Network Security Group for you. To apply it to a VM or subnet that can be achieved using the following Azure cmdlets:

  • For a subnet: Set-AzureNetworkSecurityGroupToSubnet -Name "VS-DMZ-NSG"  -VirtualNetworkName "VS-MAIN" -SubnetName "VS-DMZ-NSG"
  • For a VM: Get-AzureVM -ServiceName "DMZ" -Name "DMZ-WEB01" | Set-AzureNetworkSecurityGroupConfig -NetworkSecurityGroupName "VS-DMZ-NSG" | Update-AzureVM

The Script will not amend or remove the default Azure Network Security Group Rules.

The script can be downloaded from here.

You will need to have the Azure PowerShell module installed on the machine where the PowerShell is executed. You can obtain the Azure PowerShell cmdlets using the Web Platform Installer.

As always, test it first, make sure you’re happy with it. Feel free to leave comments below if you think there’s a way of improving it!

Azure Internal Load Balancer and the Windows Azure Pack

I’ve been working with a customer who have been developing their own custom portal for the Windows Azure Pack (WAP) and wanted to host WAP in Azure as they had two datacentres and wanted to ensure that WAP was hosted elsewhere. So in this design my Inframon colleagues and I decided to use Azure to host WAP, ADFS, SQL AlwaysOn for WAP and a few other components (not SMA and SPF though).

The design called for two servers hosting WAP (to start with) to be deployed in Azure and to have all the different WAP components (Tenant API, Tenant Public API, Admin API, etc.) load balanced using the Azure Internal Load Balancer. This also required that we changed the FQDN for the different WAP components and create a DNS entry pointing to the Azure Load Balancer’s IP address.

The diagram below shows the desired installation:


Whilst there is a great deal of documentation from Microsoft about how to use the Azure Internal Load Balancer to create a SQL AlwaysOn cluster – which was very useful as we needed one of those for WAP’s databases – there wasn’t very much about using it for anything else.

After many late nights trying to get the Azure Internal Load Balancer to do what we required we started to understand the issues we were having. We had configured the probe port to use the port that WAP was listening on (we didn’t need to change the default WAP port numbers as the customer was happy for them to remain as default as WAP wasn’t customer facing). For example to load balance the Admin API that is on port 30004 we created an Azure Endpoint using the following PowerShell:

Add-AzureInternalLoadBalancer -InternalLoadBalancerName "WAP" -ServiceName "WAP" -StaticVNetIPAddress -SubnetName "WAP"

$Port = 30004

$WAP1 = Get-AzureVM -ServiceName "WAP" -Name "WAP1"
$WAP2 = Get-AzureVM -ServiceName "WAP" -Name "WAP2"

Add-AzureEndpoint -Name "WAP$Port" -Protocol tcp -LocalPort $Port -PublicPort $Port -DirectServerReturn $false -LBSetName "WAP$Port" -ProbePort $Port -ProbeProtocol http -ProbeIntervalInSeconds 15 -ProbeTimeoutInSeconds 31 -InternalLoadBalancerName WAP -ProbePath / -VM $WAP1

Add-AzureEndpoint -Name "WAP$Port" -Protocol tcp -LocalPort $Port -PublicPort $Port -DirectServerReturn $false -LBSetName "WAP$Port" -ProbePort $Port -ProbeProtocol http -ProbeIntervalInSeconds 15 -ProbeTimeoutInSeconds 31 -InternalLoadBalancerName WAP -ProbePath / -VM $WAP2

$WAP1 | Update-AzureVM
$WAP2 | Update-AzureVM

This refused to work.

Unfortunately there is no way (that I can find) to monitor the Azure Internal Load Balancer to find out what was happening with it and what errors, if any, it is receiving from load balanced servers. After much investigation we discovered that as we were using Server Name Indication in IIS the HTTP probe wasn’t working. This was because the probe wasn’t using the SNI name and was receiving back a HTTP 400 BAD REQUEST ERROR. The Azure Internal Load Balancer correctly interpreted this a service failure so the load balancer wouldn’t work.

To resolve this problem we changed the default web site in IIS to listen on port 40091, ensured there was no SNI configured and altered the PowerShell to this:

$ServiceName = ""
$InternalLoadBalancerName = ""
$InternalLoadBalancerIPAddr = ""
$SubnetName = ""

Add-AzureInternalLoadBalancer -InternalLoadBalancerName $InternalLoadBalancerName -ServiceName $ServiceName -StaticVNetIPAddress $InternalLoadBalancerIPAddr -SubnetName $SubnetName

#Get the VM configuration from Azure
$WAP1 = Get-AzureVM -ServiceName $ServiceName -Name "WAP1"
$WAP2 = Get-AzureVM -ServiceName $ServiceName -Name "WAP2"

#The list of ports to be load balanced
$Ports = @("30004","30005","30006","30020","30022","30071","30072","30081","30091")

#Iterate each port in the list creating a new endpoint within the Azure ILB for each VM and port
ForEach($Port in $Ports){

Add-AzureEndpoint -Name "WAP$Port" -Protocol tcp -LocalPort $Port -PublicPort $Port -DirectServerReturn $false -LBSetName "WAP$Port" -ProbePort 40091 -ProbeProtocol http -ProbeIntervalInSeconds 15 -ProbeTimeoutInSeconds 31 -InternalLoadBalancerName $InternalLoadBalancerName -ProbePath / -VM $WAP1
Add-AzureEndpoint -Name "WAP$Port" -Protocol tcp -LocalPort $Port -PublicPort $Port -DirectServerReturn $false -LBSetName "WAP$Port" -ProbePort 40091 -ProbeProtocol http -ProbeIntervalInSeconds 15 -ProbeTimeoutInSeconds 31 -InternalLoadBalancerName $InternalLoadBalancerName -ProbePath / -VM $WAP2


#Update the VMs in Azure with their new configuration
$WAP1 | Update-AzureVM
$WAP2 | Update-AzureVM

This resulted in a happy Azure Internal Load Balancer but not a happy WAP deployment…

As each WAP server had all of the required components, Tenant API, Tenant Public API, Admin API, etc. and the IP address of the FQDN was set to the IP address of Azure Internal Load Balancer WAP was unable to communicate with itself across components. The diagram below shows the problem:


After much deliberation on how to solve this, including moving away from the Azure Internal Load Balancer and using a 3rd party tool in Azure, it was decided that we should put an entry in each WAP server’s hosts file for the WAP FQDN to reference itself. This led to a happy deployment!

So if you’re going to use the Azure Load Internal Load Balancer for anything then make sure you understand that servers that sit behind it can’t communicate with the IP address of it. If we had WAP split into each separate component on different servers, in different subnets behind different Azure Internal Load Balancers then this would have been OK but for this customer it would’ve been too much!

Modern Style Visio Stencils for Operations Manager

I have created some more modern style Visio stencils for System Center. This time for Operations Manager!

You can download from here.

You can what they look like from here but download them, they’re free!




MDT and DaRT – Locking the Port Used for Remote Connections during OSD

The Microsoft Deployment Toolkit (MDT) brings a lot of functionality to operating system deployment (OSD) as I’m sure many of you are aware. One of the best features is the ability to incorporate the DaRT tools into the MDT boot WIM. This allows for deployment administrators to remotely connect to a device during OSD. This can be extremely useful in a situation where the device is not local to the admin.

Johan Arwidmark has a great post on how to integrate the tools into the MDT environment with ConfigMgr.

One of the issues with the default DaRT configuration is that the remote connections use a dynamic RPC port instead of a specific port during OSD. It is possible to lock down the port when using DaRT in its fully fledged mode however locking it down to a specific port during the OSD phase is not easy.

I’ve recently been working at a customer who have VERY strict firewall policies in place and would not allow dynamic RPC ports to be open from the ConfigMgr Primary Site Server VLAN to the client device VLAN. This led me to investigate how to lock the port used by DaRT during OSD for remote connections.

After trying several different options, including adding a customised DartConfig.dat file to the base file, I was almost at the point of giving up, I didn’t.

Using the DaRT Recovery Image Wizard I created a DaRT image for Windows 8.1 Update and on the Remote Connection tab I enabled the option to Allow Remote Connections and specified a port to use, in this case 3389 as this was what the customer wanted to use:


During the process I ticked the option to edit the image before the WIM was created:


I then opened the location where the WIM contents were stored and navigated to the Windows\System32 folder to extract the customised DartConfig.dat file:


This file was then copied to a new folder where I’d created a folder structure Windows\System32:


I then finish the DaRT Recovery Image Wizard and started to create a new boot image in ConfigMgr using the “Create Boot Image using MDT” option. During the creation wizard I ticked the “Add extra files to the new boot image” option and pointed to the UNC path folder for the folder I had created above:


This created the boot image and crucially overwrote the default DartConfig.dat file with the one I created earlier. This meant that for all Task Sequences using this boot image the customer would be able to connect to the device using the DaRT Remote Control option in MDT using port 3389 at all times.



Microsoft Modern Style Visio Stencils for System Center

I have created some modern style Visio stencils for the following System Center products:

  • Virtual Machine Manager
  • Data Protection Manager
  • Configuration Manager
  • Orchestrator

They can be downloaded from here. If when I get time I’ll take a look at the other products…

%d bloggers like this: