WebServer Deployment with Load Balancer using ARM Template and Powerhell DSC

Today I am going to show you how to prepare and deploy Web Servers using ARM template with IIS roles installed on the server.

If you never have used ARM templates but want to start somewhere, check Azure Quickstart Templates on Github. It is going to be a good start for you. You can download the template locally, edit it according to your needs and then deploy it. There are few different ways how to deploy ARM template. Check which one is the best for you:

  1. Deploy via Visual Studio
  2. Download azuredeploy.json file, copy the context, go to Azure portal, click New – Template deployment – Edit template, paste the content and deploy directly through the portal
  3. Initiate azuredeploy.json file deployment with the Powershell or,
  4. On github.com just click the button Deploy to Azure and the solution will be forwarded directly to your Azure portal.

Anyway, lets go through the json template file to deploy our Network Load Balancer in front of two Web Servers.

In the parameters section I put the parameters which can be dynamically used for the input during the deployment. Few areas I want to highlight:

    • dnsNameforLBIP – unique dns name for Load Balancer
    • VMSize – Plan for your VM. It is important to note to which Azure region you are going to deploy your VMs. For example I am deploying my solutions to UK South and if I put Standard_D2 plan it will fail, because there are no such plan for the VMs within the datacenter. If you want to check VM sizes available in the specific Azure region, login to your Azure subscription with Powershell and run the following:
Get-AzureRmVMSize -Location "Uk South"

And you get all available sizes for your VM deployment in that specific region:

Name                   NumberOfCores MemoryInMB MaxDataDiskCount OSDiskSizeInMB ResourceDiskSizeInMB
----                   ------------- ---------- ---------------- -------------- --------------------
Standard_A0                        1        768                1        1047552                20480
Standard_A1                        1       1792                2        1047552                71680
Standard_A2                        2       3584                4        1047552               138240
Standard_A3                        4       7168                8        1047552               291840
Standard_A5                        2      14336                4        1047552               138240
Standard_A4                        8      14336               16        1047552               619520
Standard_A6                        4      28672                8        1047552               291840
Standard_A7                        8      57344               16        1047552               619520
Basic_A0                           1        768                1        1047552                20480
Basic_A1                           1       1792                2        1047552                40960
Basic_A2                           2       3584                4        1047552                61440
Basic_A3                           4       7168                8        1047552               122880
Basic_A4                           8      14336               16        1047552               245760
Standard_D1_v2                     1       3584                2        1047552                51200
Standard_D2_v2                     2       7168                4        1047552               102400
Standard_D3_v2                     4      14336                8        1047552               204800
Standard_D4_v2                     8      28672               16        1047552               409600
Standard_D5_v2                    16      57344               32        1047552               819200
Standard_D11_v2                    2      14336                4        1047552               102400
Standard_D12_v2                    4      28672                8        1047552               204800
Standard_D13_v2                    8      57344               16        1047552               409600
Standard_D14_v2                   16     114688               32        1047552               819200
Standard_D15_v2                   20     143360               40        1047552               286720
Standard_D2_v2_Promo               2       7168                4        1047552               102400
Standard_D3_v2_Promo               4      14336                8        1047552               204800
Standard_D4_v2_Promo               8      28672               16        1047552               409600
Standard_D5_v2_Promo              16      57344               32        1047552               819200
Standard_D11_v2_Promo              2      14336                4        1047552               102400
Standard_D12_v2_Promo              4      28672                8        1047552               204800
Standard_D13_v2_Promo              8      57344               16        1047552               409600
Standard_D14_v2_Promo             16     114688               32        1047552               819200
Standard_F1                        1       2048                2        1047552                16384
Standard_F2                        2       4096                4        1047552                32768
Standard_F4                        4       8192                8        1047552                65536
Standard_F8                        8      16384               16        1047552               131072
Standard_F16                      16      32768               32        1047552               262144
Standard_DS1_v2                    1       3584                2        1047552                 7168
Standard_DS2_v2                    2       7168                4        1047552                14336
Standard_DS3_v2                    4      14336                8        1047552                28672
Standard_DS4_v2                    8      28672               16        1047552                57344
Standard_DS5_v2                   16      57344               32        1047552               114688
Standard_DS11_v2                   2      14336                4        1047552                28672
Standard_DS12_v2                   4      28672                8        1047552                57344
Standard_DS13_v2                   8      57344               16        1047552               114688
Standard_DS14_v2                  16     114688               32        1047552               229376
Standard_DS15_v2                  20     143360               40        1047552               286720
Standard_DS2_v2_Promo              2       7168                4        1047552                14336
Standard_DS3_v2_Promo              4      14336                8        1047552                28672
Standard_DS4_v2_Promo              8      28672               16        1047552                57344
Standard_DS5_v2_Promo             16      57344               32        1047552               114688
Standard_DS11_v2_Promo             2      14336                4        1047552                28672
Standard_DS12_v2_Promo             4      28672                8        1047552                57344
Standard_DS13_v2_Promo             8      57344               16        1047552               114688
Standard_DS14_v2_Promo            16     114688               32        1047552               229376
Standard_F1s                       1       2048                2        1047552                 4096
Standard_F2s                       2       4096                4        1047552                 8192
Standard_F4s                       4       8192                8        1047552                16384
Standard_F8s                       8      16384               16        1047552                32768
Standard_F16s                     16      32768               32        1047552                65536
Standard_A1_v2                     1       2048                2        1047552                10240
Standard_A2m_v2                    2      16384                4        1047552                20480
Standard_A2_v2                     2       4096                4        1047552                20480
Standard_A4m_v2                    4      32768                8        1047552                40960
Standard_A4_v2                     4       8192                8        1047552                40960
Standard_A8m_v2                    8      65536               16        1047552                81920
Standard_A8_v2                     8      16384               16        1047552                81920
  • DSCextURL – it is public endpoint and this is where the DSC extension needs to be stored. We will check and deploy this prerequisite later on on Azure Blob storage
  • DSCSriptName – Name of the DSC file itself. In this example I am using IIS.ps1
  • DSCfunctionName – Name of the function within the IIS.ps1 file. You can have multiple functions within ps1, but in this example I am using only one, which is called Main
{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Admin username"
      }
    },
    "adminPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Admin password"
      }
    },
    "dnsNameforLBIP": {
      "type": "string",
      "metadata": {
        "description": "DNS for Load Balancer IP"
      }
    },
    "vmNamePrefix": {
      "type": "string",
      "defaultValue": "WebServer-",
      "metadata": {
        "description": "Prefix to use for VM names"
      }
    },
    "vnetName": {
      "type": "string",
      "defaultValue": "VNET",
      "metadata": {
        "description": "VNET name"
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_D2_v2",
      "metadata": {
        "description": "Size of the VM"
      }
    },
    "addressPrefix": {
      "type": "string",
      "defaultValue": "10.0.0.0/16",
      "metadata": {
        "description": "VNET IP address preffix"
      }
    },
    "SubnetName": {
      "type": "string",
      "defaultValue": "Subnet-1",
      "metadata": {
        "description": "Subnet Name"
      }
    },
    "subnetPrefix": {
      "type": "string",
      "defaultValue": "10.0.0.0/24",
      "metadata": {
        "description": "Subnet IP address preffix"
      }
    },
    "DSCextURL": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "URL where DSC extension is stored"
      }
    },
    "DSCscriptName": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "DSC script name *.ps1"
      }
    },
    "DSCfunctionName": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "DSC function name within ps1 script"
      }
    }
  },

So this is the parameters section and everything can be used as a random input. If you are thinking of multiple deployments, think which parameters can be randomised. For example if you hardcode dnsNameforLBIP it will execute only the first time and the second time will give you error messages because dns name must be unique.

Let’s check the variable section. I always put there everything what I know I will not be changing and can stay static.

  "variables": {
    "storageAccountType": "Standard_LRS",
    "availabilitySetName": "WebServerAvSet",
    "storageAccountName": "[toLower( concat('diagnos', uniqueString(resourceGroup().id)))]",
    "publicIPAddressType": "Dynamic",
    "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('vnetName'))]",
    "subnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('subnetName'))]",
    "publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]",
    "publicIPAddressName": "PublicIP",
    "nicNamePrefix": "nic",
    "numberOfInstances": 2,
    "lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('lbName'))]",
    "lbName": "internalLB",
    "frontEndIPConfigID": "[concat(variables('lbID'),'/frontendIPConfigurations/LoadBalancerFrontEnd')]",
    "lbPoolID": "[concat(variables('lbID'),'/backendAddressPools/BackendPool1')]",
    "lbProbeID": "[concat(variables('lbID'),'/probes/tcpProbe')]",
    "imagePublisher": "MicrosoftWindowsServer",
    "imageOffer": "WindowsServer",
    "imageSKU": "2012-R2-Datacenter"
 },

And the rest of the resources and dependencies go to the resource section of the ARM template. Define and deploy storage accounts, availability sets, virtual networks, load balancer with front and back end configuration, rules, probes, etc. And Virtual Machines with the resource dependencies. On top of that I have to add Powershell DSC extension to let the servers “know” what additional post deployment configuration I want to have. The rest of the ARM template is as per below:

  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "name": "[variables('storageAccountName')]",
      "apiVersion": "2015-05-01-preview",
      "location": "[resourceGroup().location]",
      "properties": {
        "accountType": "[variables('storageAccountType')]"
      }
    },
    {
      "type": "Microsoft.Compute/availabilitySets",
      "name": "[variables('availabilitySetName')]",
      "apiVersion": "2016-04-30-preview",
      "location": "[resourceGroup().location]",
      "properties": {
        "platformFaultDomainCount": "2",
        "platformUpdateDomainCount": "2",
        "managed": "true"
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[variables('publicIPAddressName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "publicIPAllocationMethod": "[variables('publicIPAddressType')]",
        "dnsSettings": {
          "domainNameLabel": "[parameters('dnsNameforLBIP')]"
        }
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "type": "Microsoft.Network/virtualNetworks",
      "name": "[parameters('vnetName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[parameters('addressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[parameters('subnetName')]",
            "properties": {
              "addressPrefix": "[parameters('subnetPrefix')]"
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('nicNamePrefix'), copyindex())]",
      "location": "[resourceGroup().location]",
      "copy": {
        "name": "nicLoop",
        "count": "[variables('numberOfInstances')]"
      },
      "dependsOn": [
        "[concat('Microsoft.Network/virtualNetworks/', parameters('vnetName'))]",
        "[concat('Microsoft.Network/loadBalancers/', variables('lbName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnetRef')]"
              },
              "loadBalancerBackendAddressPools": [
                {
                  "id": "[concat(variables('lbID'), '/backendAddressPools/BackendPool1')]"
                }
              ],
              "loadBalancerInboundNatRules": [
                {
                  "id": "[concat(variables('lbID'),'/inboundNatRules/RDP-VM', copyindex())]"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "name": "[variables('lbName')]",
      "type": "Microsoft.Network/loadBalancers",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
      ],
      "properties": {
        "frontendIPConfigurations": [
          {
            "name": "LoadBalancerFrontEnd",
            "properties": {
              "publicIPAddress": {
                "id": "[variables('publicIPAddressID')]"
              }
            }
          }
        ],
        "backendAddressPools": [
          {
            "name": "BackendPool1"
          }
        ],
        "inboundNatRules": [
          {
            "name": "RDP-VM0",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[variables('frontEndIPConfigID')]"
              },
              "protocol": "tcp",
              "frontendPort": 50001,
              "backendPort": 3389,
              "enableFloatingIP": false
            }
          },
          {
            "name": "RDP-VM1",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[variables('frontEndIPConfigID')]"
              },
              "protocol": "tcp",
              "frontendPort": 50002,
              "backendPort": 3389,
              "enableFloatingIP": false
            }
          }
        ],
        "loadBalancingRules": [
          {
            "name": "LBRule",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[variables('frontEndIPConfigID')]"
              },
              "backendAddressPool": {
                "id": "[variables('lbPoolID')]"
              },
              "protocol": "tcp",
              "frontendPort": 80,
              "backendPort": 80,
              "enableFloatingIP": false,
              "idleTimeoutInMinutes": 5,
              "probe": {
                "id": "[variables('lbProbeID')]"
              }
            }
          }
        ],
        "probes": [
          {
            "name": "tcpProbe",
            "properties": {
              "protocol": "tcp",
              "port": 80,
              "intervalInSeconds": 5,
              "numberOfProbes": 2
            }
          }
        ]
      }

    },
    {
      "apiVersion": "2016-04-30-preview",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat(parameters('vmNamePrefix'), copyindex())]",
      "copy": {
        "name": "virtualMachineLoop",
        "count": "[variables('numberOfInstances')]"
      },
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
        "[concat('Microsoft.Network/networkInterfaces/', variables('nicNamePrefix'), copyindex())]",
        "[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[concat(parameters('vmNamePrefix'), copyIndex())]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('imageSKU')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('nicNamePrefix'),copyindex()))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": "true",
            "storageUri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]"
          }
        }
      },
        "resources": [
            {
                "name": "Microsoft.Powershell.DSC",
                "type": "extensions",
                "location": "[resourceGroup().location]",
                "apiVersion": "2016-03-30",
                "dependsOn": [
                    "[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('vmNamePrefix'), copyindex()))]"
                ],
                "tags": {
                    "displayName": "IIS"
                },
              "properties": {
                "publisher": "Microsoft.Powershell",
                "type": "DSC",
                "typeHandlerVersion": "2.9",
                "autoUpgradeMinorVersion": true,
                "settings": {
                  "wmfVersion": "latest",
                  "configuration": {
                    "url": "[parameters('DSCextURL')]",
                    "script": "[parameters('DSCscriptName')]",
                    "function": "[parameters('DSCfunctionName')]"
                  },
                  "ConfigurationArguments": {
                    "nodename": "[concat(parameters('vmNamePrefix'), copyindex())]"
                  }
                },
                "protectedSettings": {}
              }
            }
        ]
    }
  ]
}

Now lets check IIS.ps1 file structure which we will need to provide to execute part of the deployment.

Configuration Main
{

Param ( [string] $nodeName )

Import-DscResource -ModuleName PSDesiredStateConfiguration

Node $nodeName
  {
    #Install the IIS Role
    WindowsFeature IIS
    {
      Ensure = “Present”
      Name = “Web-Server”
    }

    #Install ASP.NET 4.5
    WindowsFeature ASP
    {
      Ensure = “Present”
      Name = “Web-Asp-Net45”
    }

     WindowsFeature WebServerManagementConsole
    {
        Name = "Web-Mgmt-Console"
        Ensure = "Present"
    }
  }
}

Now after we have the project ready to be deployed, let’s go through the prerequisites:

  1. We have to create storage account with container type Container, which is going to be publicly available endpoint
  2. We will upload our IIS.ps1 file to this container
  3. We will get URL of that file
  4. Perform the deployment of the solution

I will go through the steps 1-3 and show you how to do it in powershell. Step 4 we will do it through the Visual Studio.

So first I put the variables in place, then I create Resource Group, storage account, container and upload my IIS.ps1. Keep in mind after the upload (Publish-AzureRmVMDscConfiguration) the file will be stored with *.zip extension. Lastly, we get the url address of the location.

$rgSolution = 'WebServers'
$location = 'UK South'
$storageAccforDSC = 'saforpshelldsc'
$Container = 'dsc'

$localPathtoDSC = 'D:\OneDrive\Cloud\Powershell\VMs+IIS'
$DSCscriptName = 'IIS.ps1'


New-AzureRmResourceGroup -Name $rgSolution -Location $Location -Verbose
New-AzureRmStorageAccount -ResourceGroupName $rgSolution -AccountName $storageAccforDSC -Location $location -SkuName "Standard_LRS" -Kind "BlobStorage" -AccessTier Cool


$saKey = (Get-AzureRmStorageAccountKey -ResourceGroupName $rgSolution -Name $storageAccforDSC).value[0]
$context = New-AzureStorageContext -StorageAccountName $storageAccforDSC -StorageAccountKey $saKey -Protocol Https
New-AzureStorageContainer -Name $container -Permission Container -Context $context

$path = "$localPathtoDSC\$DSCscriptName"

$DSCextURL = Publish-AzureRmVMDscConfiguration -ConfigurationPath $path -ResourceGroupName $rgSolution -StorageAccountName $storageAccforDSC -ContainerName $Container
$DSCextURL

Now it is time to deploy the solution with Visual Studio. I provide the values as per below and good to go!

The solution has been deployed. Now lets jump on the server to confirm if IIS role has been deployed.

And it is! Great success!

Click below to get whole json template file of this solution.

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Admin username"
      }
    },
    "adminPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Admin password"
      }
    },
    "dnsNameforLBIP": {
      "type": "string",
      "metadata": {
        "description": "DNS for Load Balancer IP"
      }
    },
    "vmNamePrefix": {
      "type": "string",
      "defaultValue": "WebServer-",
      "metadata": {
        "description": "Prefix to use for VM names"
      }
    },
    "vnetName": {
      "type": "string",
      "defaultValue": "VNET",
      "metadata": {
        "description": "VNET name"
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_D2_v2",
      "metadata": {
        "description": "Size of the VM"
      }
    },
    "addressPrefix": {
      "type": "string",
      "defaultValue": "10.0.0.0/16",
      "metadata": {
        "description": "VNET IP address preffix"
      }
    },
    "SubnetName": {
      "type": "string",
      "defaultValue": "Subnet-1",
      "metadata": {
        "description": "Subnet Name"
      }
    },
    "subnetPrefix": {
      "type": "string",
      "defaultValue": "10.0.0.0/24",
      "metadata": {
        "description": "Subnet IP address preffix"
      }
    },
    "DSCextURL": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "URL where DSC extension is stored"
      }
    },
    "DSCscriptName": {
      "type": "string",
      "defaultValue": "IIS.ps1",
      "metadata": {
        "description": "DSC script name *.ps1"
      }
    },
    "DSCfunctionName": {
      "type": "string",
      "defaultValue": "Main",
      "metadata": {
        "description": "DSC function name within ps1 script"
      }
    }
  },
  "variables": {
    "storageAccountType": "Standard_LRS",
    "availabilitySetName": "WebServerAvSet",
    "storageAccountName": "[toLower( concat('diagnos', uniqueString(resourceGroup().id)))]",
    "publicIPAddressType": "Dynamic",
    "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('vnetName'))]",
    "subnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('subnetName'))]",
    "publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]",
    "publicIPAddressName": "PublicIP",
    "nicNamePrefix": "nic",
    "numberOfInstances": 2,
    "lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('lbName'))]",
    "lbName": "internalLB",
    "frontEndIPConfigID": "[concat(variables('lbID'),'/frontendIPConfigurations/LoadBalancerFrontEnd')]",
    "lbPoolID": "[concat(variables('lbID'),'/backendAddressPools/BackendPool1')]",
    "lbProbeID": "[concat(variables('lbID'),'/probes/tcpProbe')]",
    "imagePublisher": "MicrosoftWindowsServer",
    "imageOffer": "WindowsServer",
    "imageSKU": "2012-Datacenter"
    
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "name": "[variables('storageAccountName')]",
      "apiVersion": "2015-05-01-preview",
      "location": "[resourceGroup().location]",
      "properties": {
        "accountType": "[variables('storageAccountType')]"
      }
    },
    {
      "type": "Microsoft.Compute/availabilitySets",
      "name": "[variables('availabilitySetName')]",
      "apiVersion": "2016-04-30-preview",
      "location": "[resourceGroup().location]",
      "properties": {
        "platformFaultDomainCount": "2",
        "platformUpdateDomainCount": "2",
        "managed": "true"
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[variables('publicIPAddressName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "publicIPAllocationMethod": "[variables('publicIPAddressType')]",
        "dnsSettings": {
          "domainNameLabel": "[parameters('dnsNameforLBIP')]"
        }
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "type": "Microsoft.Network/virtualNetworks",
      "name": "[parameters('vnetName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[parameters('addressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[parameters('subnetName')]",
            "properties": {
              "addressPrefix": "[parameters('subnetPrefix')]"
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('nicNamePrefix'), copyindex())]",
      "location": "[resourceGroup().location]",
      "copy": {
        "name": "nicLoop",
        "count": "[variables('numberOfInstances')]"
      },
      "dependsOn": [
        "[concat('Microsoft.Network/virtualNetworks/', parameters('vnetName'))]",
        "[concat('Microsoft.Network/loadBalancers/', variables('lbName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnetRef')]"
              },
              "loadBalancerBackendAddressPools": [
                {
                  "id": "[concat(variables('lbID'), '/backendAddressPools/BackendPool1')]"
                }
              ],
              "loadBalancerInboundNatRules": [
                {
                  "id": "[concat(variables('lbID'),'/inboundNatRules/RDP-VM', copyindex())]"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2015-05-01-preview",
      "name": "[variables('lbName')]",
      "type": "Microsoft.Network/loadBalancers",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
      ],
      "properties": {
        "frontendIPConfigurations": [
          {
            "name": "LoadBalancerFrontEnd",
            "properties": {
              "publicIPAddress": {
                "id": "[variables('publicIPAddressID')]"
              }
            }
          }
        ],
        "backendAddressPools": [
          {
            "name": "BackendPool1"
          }
        ],
        "inboundNatRules": [
          {
            "name": "RDP-VM0",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[variables('frontEndIPConfigID')]"
              },
              "protocol": "tcp",
              "frontendPort": 50001,
              "backendPort": 3389,
              "enableFloatingIP": false
            }
          },
          {
            "name": "RDP-VM1",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[variables('frontEndIPConfigID')]"
              },
              "protocol": "tcp",
              "frontendPort": 50002,
              "backendPort": 3389,
              "enableFloatingIP": false
            }
          }
        ],
        "loadBalancingRules": [
          {
            "name": "LBRule",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[variables('frontEndIPConfigID')]"
              },
              "backendAddressPool": {
                "id": "[variables('lbPoolID')]"
              },
              "protocol": "tcp",
              "frontendPort": 80,
              "backendPort": 80,
              "enableFloatingIP": false,
              "idleTimeoutInMinutes": 5,
              "probe": {
                "id": "[variables('lbProbeID')]"
              }
            }
          }
        ],
        "probes": [
          {
            "name": "tcpProbe",
            "properties": {
              "protocol": "tcp",
              "port": 80,
              "intervalInSeconds": 5,
              "numberOfProbes": 2
            }
          }
        ]
      }

    },
    {
      "apiVersion": "2016-04-30-preview",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat(parameters('vmNamePrefix'), copyindex())]",
      "copy": {
        "name": "virtualMachineLoop",
        "count": "[variables('numberOfInstances')]"
      },
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
        "[concat('Microsoft.Network/networkInterfaces/', variables('nicNamePrefix'), copyindex())]",
        "[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[concat(parameters('vmNamePrefix'), copyIndex())]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('imageSKU')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('nicNamePrefix'),copyindex()))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": "true",
            "storageUri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]"
          }
        }
      },
        "resources": [
            {
                "name": "Microsoft.Powershell.DSC",
                "type": "extensions",
                "location": "[resourceGroup().location]",
                "apiVersion": "2016-03-30",
                "dependsOn": [
                    "[resourceId('Microsoft.Compute/virtualMachines', concat(parameters('vmNamePrefix'), copyindex()))]"
                ],
                "tags": {
                    "displayName": "IIS"
                },
              "properties": {
                "publisher": "Microsoft.Powershell",
                "type": "DSC",
                "typeHandlerVersion": "2.9",
                "autoUpgradeMinorVersion": true,
                "settings": {
                  "wmfVersion": "latest",
                  "configuration": {
                    "url": "[parameters('DSCextURL')]",
                    "script": "[parameters('DSCscriptName')]",
                    "function": "[parameters('DSCfunctionName')]"
                  },
                  "ConfigurationArguments": {
                    "nodename": "[concat(parameters('vmNamePrefix'), copyindex())]"
                  }
                },
                "protectedSettings": {}
              }
            }
        ]
    }
  ]
}

Let me know what you think in the comments below and thanks for reading!

MagicM.

Leave a Reply

Your email address will not be published.