none
Question about deploying multiple VMs with template

    Question

  • Hi guys,

    I would like to create a template that will create multiple VMs per users with their name on the resource, for example :

    test-dc-user1 and test-dc-nic-user1

    test-svr-user1 and test-svr-nic-user1

    test-client-user1 and test-client-nic-user1

    And same for user2, etc., but all of this with the same template, is it possible? If yes, do you have an example?

    Thanks.

    Monday, March 20, 2017 9:32 AM

Answers

  • There is no need to use scale sets to achieve what you want to do, you can do so using the CopyIndex function of the Arm template.

    By specifying this for your resource, you can create multiple copies of the resource, for example the below creates multiple web apps, based on a count  passed as a parameter:

     { 
          "name": "[concat('examplecopy-', copyIndex())]", 
          "type": "Microsoft.Web/sites", 
          "location": "East US", 
          "apiVersion": "2015-08-01",
          "copy": { 
             "name": "websitescopy", 
             "count": "[parameters('count')]" 
          }, 
          "properties": {
              "serverFarmId": "hostingPlanName"
          }
      } 

    When you do this, you can then use the copyIndex inside teh resource for naming etc. In this example it is used in the name:

    "[concat('examplecopy-', copyIndex())]",

    This will create names of examplecopy-1, examplcopy-2 etc.

    Where you need multiple resources like VM's, NICS etc you just use the same copyIndex parameter for each resource to get the same number of NICS as VM's, then when you reference the NIC in teh VM you use the copyIndex to get the NIC name.

    See this article for more details and examples.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    • Marked as answer by Olddddd Thursday, March 23, 2017 2:50 PM
    Tuesday, March 21, 2017 9:30 AM

All replies

  • You can deploy multiple VM using the template. Virtual machine scale sets are an Azure Compute resource to deploy and manage a set of identical VMs. Refer the below article “Deploy multiple VMs from template with PowerCLI”.

    http://www.harryjohn.org/deploy-multiple-vms-from-template/

    https://communities.vmware.com/thread/455410

    For my information, you are planning to use multiple NIC’s or same NIC for creating multiple VM?

    Disclaimer: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet.

    Tuesday, March 21, 2017 3:38 AM
    Moderator
  • It's for a school environment, so each student need to have 3 VMs with 3 different NICs, and I don't need to scale my VMs because I know in advance how many students I will have and the VMs need to be fixed.

    The two links you provided me doesn't match with what I would like to do, I found a better link on Microsoft Doc : https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple

    But I have some questions, is it possible to have dynamic boxes (parameters) within the template deployment blade? For example, if I don't know how many students I will have and what will be their names, is it possible to have a parameter named "number of users", and when I assign a number to it, let's say 10, automatically 10 boxes are created for the users names, is it possible?

    If not, do you have an idea how can I name my VMs like that :

    test-dc-user1 with test-dc-nic-user1

    test-svr-user1 with test-svr-nic-user1

    test-client-user1 with ...

    test-dc-user2

    test-svr-user2

    test-client-user2

    and so on...

    Or maybe I will need to create a template for each VMs, for example, a template that creat all the users DCs, another for the users servers and the last for the users clients machines?


    • Edited by Olddddd Tuesday, March 21, 2017 9:22 AM
    Tuesday, March 21, 2017 8:09 AM
  • There is no need to use scale sets to achieve what you want to do, you can do so using the CopyIndex function of the Arm template.

    By specifying this for your resource, you can create multiple copies of the resource, for example the below creates multiple web apps, based on a count  passed as a parameter:

     { 
          "name": "[concat('examplecopy-', copyIndex())]", 
          "type": "Microsoft.Web/sites", 
          "location": "East US", 
          "apiVersion": "2015-08-01",
          "copy": { 
             "name": "websitescopy", 
             "count": "[parameters('count')]" 
          }, 
          "properties": {
              "serverFarmId": "hostingPlanName"
          }
      } 

    When you do this, you can then use the copyIndex inside teh resource for naming etc. In this example it is used in the name:

    "[concat('examplecopy-', copyIndex())]",

    This will create names of examplecopy-1, examplcopy-2 etc.

    Where you need multiple resources like VM's, NICS etc you just use the same copyIndex parameter for each resource to get the same number of NICS as VM's, then when you reference the NIC in teh VM you use the copyIndex to get the NIC name.

    See this article for more details and examples.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    • Marked as answer by Olddddd Thursday, March 23, 2017 2:50 PM
    Tuesday, March 21, 2017 9:30 AM
  • I already saw this article, but I didin't find a way to do it like I want, the article gives only the possibility to create resources based on a number or on an array of strings, but what I want to do is more complex, I would like to do something like that:

    Create 3 VMs (Windows or Linux) and their NICs per users with their names on it:

    example-dc-user1 and example-dc-nic-user1

    example-svr1-user1 and example-svr1-nic-user1

    example-svr2-user1 and example-svr2-nic-user1

    And do the same with all my other users, I provide in my template an array with the user names (user1, user2, etc.).


    • Edited by Olddddd Tuesday, March 21, 2017 10:02 AM
    Tuesday, March 21, 2017 10:01 AM
  • You would pass in your list of students as an array, then use the size of this array as your count variable:

    "copy": {
        "name": "websitescopy",
        "count": "[length(parameters('studentNames'))]"
    }

    Then when it came to naming things you would do a lookup inside that array using the copy index

    "Name":"[concat('example-dc-', parameters('studentNames[copyIndex()]'))]",




    Sam Cogan Microsoft Azure MVP
    Blog | Twitter


    • Edited by SamCoganMVP Tuesday, March 21, 2017 10:31 AM
    Tuesday, March 21, 2017 10:30 AM
  • That's what I did, but I can't do the same for example-svr1 and example-svr2 within the same template, I need to create two more templates for that, right?

    And about your line:

    "Name":"[concat('example-dc-', parameters('studentNames[copyIndex()]'))]",

    It's not like that rather:

    "Name":"[concat('example-dc-', parameters('studentNames')[copyIndex()])]",

    Like it's written in the doc?

    Tuesday, March 21, 2017 10:54 AM
  • Or maybe, can I create 3 VMs and NICs resources within my template, and assign a different loop for each?

    Something like that :

    "resources": [

    {
                "type": "Microsoft.Network/networkInterfaces",
                "name": "[concat('schl-dc-nic-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2016-03-30",
                "location": "[variables('location')]",
                "copy": {
                    "name": "nicscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "ipConfigurations": [
                        {
                            "name": "ipconfig1",
                            "properties": {
                                "privateIPAllocationMethod": "Dynamic",
                                "subnet": {
                                    "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('vnetName')), '/subnets/labsubnet')]"
                                }
                            }
                        }
                    ],
                    "dnsSettings": {
                        "dnsServers": []
                    },
                    "enableIPForwarding": false,
                    "networkSecurityGroup": {
                        "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgReference'))]"
                    }
                },
                "dependsOn": [
                    "[resourceId('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
                ]
            },
            {
                "type": "Microsoft.Network/networkInterfaces",
                "name": "[concat('schl-svr1-nic-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2016-03-30",
                "location": "[variables('location')]",
                "copy": {
                    "name": "nicscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "ipConfigurations": [
                        {
                            "name": "ipconfig1",
                            "properties": {
                                "privateIPAllocationMethod": "Dynamic",
                                "subnet": {
                                    "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('vnetName')), '/subnets/labsubnet')]"
                                }
                            }
                        }
                    ],
                    "dnsSettings": {
                        "dnsServers": []
                    },
                    "enableIPForwarding": false,
                    "networkSecurityGroup": {
                        "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgReference'))]"
                    }
                },
                "dependsOn": [
                    "[resourceId('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
                ]
            },
            {
                "type": "Microsoft.Network/networkInterfaces",
                "name": "[concat('schl-svr2-nic-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2016-03-30",
                "location": "[variables('location')]",
                "copy": {
                    "name": "nicscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "ipConfigurations": [
                        {
                            "name": "ipconfig1",
                            "properties": {
                                "privateIPAllocationMethod": "Dynamic",
                                "subnet": {
                                    "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('vnetName')), '/subnets/labsubnet')]"
                                }
                            }
                        }
                    ],
                    "dnsSettings": {
                        "dnsServers": []
                    },
                    "enableIPForwarding": false,
                    "networkSecurityGroup": {
                        "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgReference'))]"
                    }
                },
                "dependsOn": [
                    "[resourceId('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
                ]
            },
            {
                "type": "Microsoft.Compute/virtualMachines",
                "name": "[concat('schl-dc-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2016-04-30-preview",
                "location": "[variables('location')]",
                "copy": {
                    "name": "vmscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "hardwareProfile": {
                        "vmSize": "[parameters('vmSize')]"
                    },
                    "storageProfile": {
                        "imageReference": "[variables('imageReference')]",
                        "osDisk": {
                            "name": "[concat('schl-dc-', parameters('studentName')[copyIndex()], parameters('OS'))]",
                            "vhd": {
                                "uri": "[variables('osDiskVhdUri')]"
                            },
                            "createOption": "FromImage"
                        }
                    },
                    "osProfile": {
                        "computerName": "[concat('schl-dc-', parameters('studentName')[copyIndex()])]",
                        "adminUsername": "[parameters('adminUsername')]",
                        "adminPassword": "[parameters('adminPassword')]"
                    },
                    "networkProfile": {
                        "networkInterfaces": [
                            {
                                "id": "[resourceId('Microsoft.Network/networkInterfaces',concat('schl-dc-nic-', copyindex()))]"
                            }
                        ]
                    }
                }
            },
            {
                "type": "Microsoft.Compute/virtualMachines",
                "name": "[concat('schl-svr1-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2016-04-30-preview",
                "location": "[variables('location')]",
                "copy": {
                    "name": "vmscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "hardwareProfile": {
                        "vmSize": "[parameters('vmSize')]"
                    },
                    "storageProfile": {
                        "imageReference": "[variables('imageReference')]",
                        "osDisk": {
                            "name": "[concat('schl-svr1-', parameters('studentName')[copyIndex()], parameters('OS'))]",
                            "vhd": {
                                "uri": "[variables('osDiskVhdUri')]"
                            },
                            "createOption": "FromImage"
                        }
                    },
                    "osProfile": {
                        "computerName": "[concat('schl-svr1-', parameters('studentName')[copyIndex()])]",
                        "adminUsername": "[parameters('adminUsername')]",
                        "adminPassword": "[parameters('adminPassword')]"
                    },
                    "networkProfile": {
                        "networkInterfaces": [
                            {
                                "id": "[resourceId('Microsoft.Network/networkInterfaces',concat('schl-svr1-nic-', copyindex()))]"
                            }
                        ]
                    }
                }
            },
            {
                "type": "Microsoft.Compute/virtualMachines",
                "name": "[concat('schl-svr2-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2016-04-30-preview",
                "location": "[variables('location')]",
                "copy": {
                    "name": "vmscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "hardwareProfile": {
                        "vmSize": "[parameters('vmSize')]"
                    },
                    "storageProfile": {
                        "imageReference": "[variables('imageReference')]",
                        "osDisk": {
                            "name": "[concat('schl-svr2-', parameters('studentName')[copyIndex()], parameters('OS'))]",
                            "vhd": {
                                "uri": "[variables('osDiskVhdUri')]"
                            },
                            "createOption": "FromImage"
                        }
                    },
                    "osProfile": {
                        "computerName": "[concat('schl-svr2-', parameters('studentName')[copyIndex()])]",
                        "adminUsername": "[parameters('adminUsername')]",
                        "adminPassword": "[parameters('adminPassword')]"
                    },
                    "networkProfile": {
                        "networkInterfaces": [
                            {
                                "id": "[resourceId('Microsoft.Network/networkInterfaces',concat('schl-svr2-nic-', copyindex()))]"
                            }
                        ]
                    }
                }
            }

    ]


    • Edited by Olddddd Tuesday, March 21, 2017 1:47 PM
    Tuesday, March 21, 2017 11:37 AM
  • Yes, that's what I was getting at, sorry if it wasn't clear. Each different type of server should be it's own resource, but then use the loop to create as many of each one as you need. It does add some duplication, but becomes even more useful if you want to start using something like DSC to configure the VM's when they are up, as each different type of server will have a different DSC configuration.

    On your question of syntax, I would trust what is in the docs, my example was just off the top of my head so entirely possible my brackets are wrong.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter


    • Edited by SamCoganMVP Tuesday, March 21, 2017 1:15 PM
    Tuesday, March 21, 2017 1:14 PM
  • Alright, I can't use an array for admin username, why?

    By default, the names are written like that in the box : "[\"user1\",\"user2\"]" but it tells me that user name cannot contain special characters.

    • Edited by Olddddd Tuesday, March 21, 2017 2:33 PM
    Tuesday, March 21, 2017 1:44 PM
  • VHD names can't have spaces in them, you'll need to remove the spaces from the name before doing so, you can use the replace function for this. So I would suggest something like:

    "name": "[concat('schl-dc-', parameters('studentName')[copyIndex()],'-',replace(parameters('OS'),' ','-'))]",

    This should produce "sch1-dc-user1-Windows-2012-R2.vhd"


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Tuesday, March 21, 2017 2:41 PM
  • Yes, I found my error before you answer, and I have modified my post with another question. ^^

    But if I want to replace space and point with "-", is it possible with replace function?

    Also, even I corrected this error, I get another one that said that my URI doesn't look to be correct blob URI, my URI looks like: https://example.blob.core.windows.net/vhds, I tried to remove the https:// but it doesn't work either.


    • Edited by Olddddd Tuesday, March 21, 2017 3:01 PM
    Tuesday, March 21, 2017 2:57 PM
  • Yes you can replace both space and point, you would just need two replace functions

    replace(replace(parameter(OS),' ','-'),'.','-')

    Not the most elegant but it works.

    Can you post the error message for your second issue please.

    Your admin username array should just be a plain array of strings, no need for escaping.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Tuesday, March 21, 2017 3:16 PM
  • Alright, thanks.

    Fixed the issue with the storage account with this:

    "osDisk": {
           "name": "[concat('schl-svr2-', parameters('studentName')[copyIndex()],'-',replace(parameters('svr2OS'),' ','-'))]",
           "vhd": {
               "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), '2016-01-01').primaryEndpoints.blob, variables('vmStorageAccountContainerName'), '/',concat('schl-dc-', parameters('studentName')[copyIndex()],'-',replace(parameters('dcOS'),' ','-')),'.vhd')]"
           },
           "createOption": "FromImage"

    It's not possible to call the name property within the uri property? If not, why I need to specify the name property if I can't use it? I made an error, the copyIndex is not compatible with property on a resource type, so how can I write this with the take function?

    EDIT : Finally, it's OK, I can use the copy function in the property of a resource, so why the doc says the opposite? There


    About admin username array, there is the error:

    For the student name box, the template wrote the names like that, I tried to do the same with the admin username but I get the same error.

    I get this error with two replace functions:

    The parenthesis looks correct.

    And about the admin username loop, is this code correct:

    "variables": {
    "userNameArray": [
                "bcarlton",
                "swill"
            ]
    },
    "resources": [
            {
                "type": "Microsoft.Compute/virtualMachines",
                "name": "[concat('schl-dc-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2016-04-30-preview",
                "location": "[variables('location')]",
                "copy": {
                    "name": "vmscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "osProfile": {
                        "computerName": "[concat('schl-dc-', parameters('studentName')[copyIndex()])]",
                        "adminUsername": "[take(variables('userNameArray'), length(variables('userNameArray')))]",
                        "adminPassword": "[parameters('adminPassword')]"
                    }
                }
            }
    ]

    I used the take function since the copy function is not compatible with resource properties.






    • Edited by Olddddd Wednesday, March 22, 2017 2:52 PM
    Tuesday, March 21, 2017 5:24 PM
  • I'm blocked, need help.
    Wednesday, March 22, 2017 12:33 PM
  • Can you please post your full Template file and any parameter files you are using.

    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Wednesday, March 22, 2017 2:56 PM
  • Here it is: http://pastebin.com/xJrRj7h2

    I didn't include the admin username array since it doesn't work.

    Wednesday, March 22, 2017 3:03 PM
  • Links not working now.

    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Wednesday, March 22, 2017 5:15 PM
    • Edited by Olddddd Wednesday, March 22, 2017 5:19 PM
    Wednesday, March 22, 2017 5:19 PM
  • Ok, I'm a bit confused now, can you please list in a new reply the issues you are currently experiencing with teh code in the pastebin. As it looks like  you have worked around some issues, which ones are actually preventing you deploying now?

    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Wednesday, March 22, 2017 5:48 PM
  • First, I don't understand why I can use the copy function within a resource property, osDisk here, while the doc says that it's not compatible and we need to use the take function instead.

    Secondly, when I want to use an array with my admin usernames, I get the error unable to parse the value into type 'array' like shows the screen above.

    Thirdly, when I use the double replace functions, I get this error during the deployment:

    Wednesday, March 22, 2017 5:57 PM
  • On the first question, I don't know, I suspect an issue with the documentation. That said, I would suggest you take a look at using managed disks for your VM's rather than the VHD and storage account approach, this means you don't need to care about VHD names and so on.

    For your admin array, how are you passing the values in when you run the deployment, are you using a parameter file, or just passing it in as part of your PowerShell command? Can  you post this.

    On your replace function, your missing some quotes around OS, it should be parameter('OS').


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Wednesday, March 22, 2017 10:13 PM
  • Alright. About managed disks, why I will not need to care about VHD names? It will rename them automatically with the VMs name? I want to facilitate the troubleshooting, that's why I care about VHD names. Also, it's the only advantage of managed disks compared to storage account? I saw that it provides scale functionality and it's better to use them with VMSS, but since I don't need scale ability and I don't use VMSS, I will use them only for my VHD names?

    For admin username array, I'm simply passing the values directly to the template file, into the parameters, like that:

    "parameters": {
    "adminUsername": {
                "type": "Array",
                "defaultValue": [
                    "bcarlton",
                    "swill"
                ],
                "metadata": {
                    "description": "Students's names for their VMs, first letter of the first name + last name"
                }
            },

    But I didn't think yet about a better way like providing names with a PowerShell or a parameter file. For PowerShell, I can provide names with the Add-Content cmdlet that will write into my template file, right? Or maybe I'm wrong? But for parameter file, I don't understand the utility since I provide already the parameters within my template file.

    Also, how can I use two copy function in the same resource, 1 for my studentName and the other for my adminUsername? copy1 with copy1Index() and copy2 with copy2Index()?

    I tried this but it doesn't work:

    {
                "type": "Microsoft.Compute/virtualMachines",
                "name": "[concat('schl-dc-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2017-03-30",
                "location": "[resourceGroup().location]",
                "copy": {
                    "name": "vmscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "copy": {
                        "name": "adminname",
                        "count": "[length(parameters('adminUsername'))]"
                    },
                    "osProfile": {
                        "computerName": "[concat('schl-dc-', parameters('studentName')[copyIndex()])]",
                        "adminUsername": "[parameters('adminUsername')[copyIndex()]]",
                        "adminPassword": "[parameters('adminPassword')]"
                    },
                }
    },

    Yes, indeed, I missed some quotes, thanks.

    • Edited by Olddddd Thursday, March 23, 2017 9:59 AM
    Thursday, March 23, 2017 8:19 AM
  • The benefit of managed disks is that you don't have to care about the underlying storage. If you use standard disks you need to create a storage account to store them in, if you have multiple VM's and you want best performance and availability you need to manually take care to spread them over multiple storage accounts. Additionally because managed disks are top level objects you can set RBAC permissions on them, to control who can manage the disk, you also have the ability to take snapshots of the disks. Finally, you don't have to deal with ensuring you name the disk uniquely, it will do it for you. You basically get a name of <vm name>_OSDisk_GUID.

    Parameter files are useful because you are separating your parameters out from your ARM template, so if you are likely to want to deploy multiple different configurations using the same template it can be really helpful. If you are only ever going to deploy this once, with one set of parameters, maybe less so. With parameter files you can have multiple different files, lets say for dev, test and prod environments, but use the same template file.

    You can't use more than one copy function inside a single resouce, it can only loop once.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Thursday, March 23, 2017 10:10 AM
  • Alright for managed disks, but it costs much more than storage account, for a S10 size with 128 GB, I need to pay €2.483 (per disk) while a storage account I pay €0.0166 (LRS-HOT) + €0.0456 and €0.0034 for operations, 0.0656 for all my VHDs, I know that I will not have all the functionality that provide managed disks, but for a school environment, I don't think they will need all of these capabilities.

    About the two copy functions, I will use the same loop that the studentName for my adminUsername, but it means that if I want to have a different name that the studentName, I can't?


    Also, why we need to specify a name for the copy function while nothing use it?
    • Edited by Olddddd Thursday, March 23, 2017 11:38 AM
    Thursday, March 23, 2017 11:28 AM
  • Yeah it's a fair point if your using standard storage. If your using premium storage, which is a must for production workloads, then the price is the same whichever way you go, but obviously that would be overkill in your situation.

    You can still have a different admin name to student, as they are different arrays, but they would have to match on the index. so student[0] would get admin[0].

    You do use the copy name in some instance, for example if you are defining a dependency, so that all of your copy loops complete before the dependent resource runs.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Thursday, March 23, 2017 5:56 PM
  • Got it.

    Something like that :

    "copy": {
         "name": "vmscopy",
         "count": "[length(parameters('studentName', 'adminUsername'))]"
            },
    			
          "computerName": "[concat('schl-dc-', parameters('studentName')[copyIndex(studentName)])]",
          "adminUsername": "[parameters('adminUsername')[copyIndex(adminUsername)]]",

    ?

    OK, thank you.

    Thursday, March 23, 2017 6:48 PM
  • No sorry, what I meant was you can only have one value in count, so you 'd have to do something like this:

    "copy": {
         "name": "vmscopy",
         "count": "[length(parameters('studentName'))]"
            },
    			
          "computerName": "[concat('schl-dc-', parameters('studentName')[copyIndex)]",
          "adminUsername": "[parameters('adminUsername')[copyIndex]]",

    This is assuming that your student and admin arrays are lined up, so adminUsername[0] is the admin name for student[0].


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Thursday, March 23, 2017 8:46 PM
  • Alright, that was what I did first, but I thought I was wrong.

    Thanks for all your help Sam!

    Thursday, March 23, 2017 8:57 PM

  • Hi again,

    Is it possible to have another adminPassword parameter in order to see if it matches with the first one to avoid misstaping?
    Monday, March 27, 2017 11:35 AM
  • No, afraid now. I mean you can have another parameter, but there is no way to compare it in your ARM template. 

    You'd need to write your own script that calls the deployment process and does this check for you.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Monday, March 27, 2017 12:01 PM
  • OK, thanks.
    Monday, March 27, 2017 12:43 PM
  • Hi,

    I created 4 extensions (2 for Windows and 2 for Linux) and 3 parameters assigned to them in order to choice which extensions add to my 3 VMs, something like that: https://pastebin.com/72Hv6N12

    The extensions need to be optional but I don't know how to do that and also, I don't know how to say in my extensions resources "install the extension only if you have been chosen".

    I don't know if I was clear, but there is an example:

    schl-user1-dc : IIS extension

    schl-user1-svr1 : no extension

    schl-user1-svr2 : LibreOffice extension

    And so on for all other users.

    Should I need to create these 4 extensions resources as 4 child extensions resources under each vm resources?


    EDIT: If there was an extension property for vm resource, it would have been easy to do it, but I didn't find it.


    • Edited by Olddddd Wednesday, March 29, 2017 8:46 AM
    Wednesday, March 29, 2017 7:48 AM
  • VM extensions can't exist as top level resources, they need to be under the VM, and you can only install 1 DSC extension per VM, so your approach won't work.

    I'm guessing what you are trying to do is re-use DSC components? If so you want to look at composite DSC resources.


    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Wednesday, March 29, 2017 12:30 PM
  • My 4 extensions:

    -DSC extensions that will install IIS

    -PowerShell script that install PuTTY

    -Linux script that install LibreOffice on Ubuntu

    -Linux script that install LibreOffice on CentOS

    For each VMs (remember, 3 per user), I want to have the choice between these 4 extensions, and of course, I will pick just 1 extension per VM. So I have already create the 4 extensions resources but I don't know how, based on the choice, install the extensions on the appropriate VMs.

    For example:

    -Install PuTTY on all DCs with the PowerShell script

    -Install IIS on all SVR1 with the DSC script

    -Install LibreOffice on all SVR2 with the Linux script

    Is not possible?

    Something like that:

    And what do you mean by "VM extensions can't exist as top level resources"? My template shows only the extensions resources, there are above them all other resources such as VMs, etc. in my complete template.

    EDIT : I've just read that is not possible to have optional parameters, so it resolve one question.

    EDIT2 : If I include the 4 extensions directly under the vm resources, the template will install the 4 extensions to all my VMs, while I want to install only the selected ones. It's not possible to create a condition like: "if selected, install" ?

    Or maybe can I do this by creating another template for these extensions?

    • Edited by Olddddd Friday, March 31, 2017 2:21 PM
    Wednesday, March 29, 2017 12:49 PM
  • Up
    Thursday, March 30, 2017 11:43 AM
  • Hi,

    After some research, I think it's not possible what I wanted to do.

    But I have another question. Is it possible for each NIC created, to put it in a different subnet, while I have already used a copy function in the NIC resource?

    {
                "type": "Microsoft.Network/networkInterfaces",
                "name": "[concat('schl-dc-nic-', parameters('studentName')[copyIndex()])]",
                "apiVersion": "2017-03-01",
                "location": "[resourceGroup().location]",
                "copy": {
                    "name": "nicscopy",
                    "count": "[length(parameters('studentName'))]"
                },
                "properties": {
                    "ipConfigurations": [
                        {
                            "name": "ipconfig1",
                            "properties": {
                                "privateIPAllocationMethod": "Dynamic",
                                "subnet": {
                                    "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('vnetName')), '/subnets/labSubnet')]"
                                }
                            }
                        }
                    ],
                    "dnsSettings": {
                        "dnsServers": []
                    },
                    "enableIPForwarding": false,
                    "networkSecurityGroup": {
                        "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgReference1'))]"
                    }
                },
                "dependsOn": [
                    "[resourceId('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
                ]
            },

    This line:

    "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('vnetName')), '/subnets/labSubnet')]"

    I created 4 subnets, named labSubnet1 --> 4, and for each NIC created, I want to assign it with a different NIC, so:

    schl-dc-nic-bob: labSubnet1
    schl-dc-nic-bill: labSubnet2
    schl-dc-nic-john: labSubnet3
    schl-dc-nic-will: labSubnet4

    Monday, April 03, 2017 2:19 PM
  • Yes, you can do that, your just going to have to do the same sort of thing and have an array of subnet names and use the copy index to reference it.

    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Monday, April 03, 2017 2:22 PM
  • Alright, thanks.

    Do you confirm also that it's not possible to do what I asked about the extensions?

    • Edited by Olddddd Monday, April 03, 2017 7:02 PM
    Monday, April 03, 2017 6:01 PM
  • I don't believe so, but i'm still not entirely clear what you are trying to achieve. If you know which extensions you need to apply to which VM's in advance, then why try and specify it as a parameter, just have them hard coded.

    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Monday, April 03, 2017 8:22 PM
  • I want to let the choice to choose the extension between the 4 I created. And also, because I don't know in advance which OS will be chosen for the dc, svr1 and svr2, I can't hard coded them directly under each VMs (I have 2 extensions for Windows and 2 for Linux).
    Tuesday, April 04, 2017 7:03 AM
  • Ok, well you can't really do any sort of If statement in an ARM template, so the only way you are really going to be able to achieve that is to have a parameter that indicates the type of deployment (or multiple parameters) which is then used as part of the URL to call a child template. Take a look at this example.

    Sam Cogan Microsoft Azure MVP
    Blog | Twitter

    Tuesday, April 04, 2017 9:31 AM
  • Alright, I will take a look at this, thanks!

    • Edited by Olddddd Tuesday, April 04, 2017 10:32 AM
    Tuesday, April 04, 2017 10:32 AM