2

I have a powershell script to install a VSTS Build Agent in an ARM template. This template is based off the azure quickstart templates here.

I want to use the "copy" function to run the script multiple times because I want to install 10 agents when my VM is deployed. When I try to deploy my template I get this error:

Error: Code=InvalidTemplate; Message=Deployment template validation failed: 
'The template resource 'CustomScript' at line '247' column '13' is not valid. Copying nested resources is not supported.

My question is, how can I install 10 build agents with the copy function so that I have vsts-agent-1, vsts-agent-2, etc?

Here's the relevant snippet of the template:

{
      "name": "[parameters('vmName')]",
      "type": "Microsoft.Compute/virtualMachines",
      "location": "[parameters('location')]",
      "apiVersion": "2017-03-30",
      "dependsOn": [
        "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
        "[concat('Microsoft.Network/networkInterfaces/', variables('vmNicName'))]"
      ],
      "tags": {
        "displayName": "VM01"
      },
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[parameters('vmName')]",
          "adminUsername": "[parameters('vmAdminUserName')]",
          "adminPassword": "[parameters('vmAdminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('vmImagePublisher')]",
            "offer": "[variables('vmImageOffer')]",
            "sku": "[parameters('vmVisualStudioVersion')]",
            "version": "latest"
          },
          "osDisk": {
            "name": "[concat(parameters('vmName'),'_OSDisk')]",
            "caching": "ReadWrite",
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('vmNicName'))]"
            }
          ]
        }
      },
      "resources": [
        {
          "name": "CustomScript",
          "type": "extensions",
          "location": "[parameters('location')]",
          "apiVersion": "2015-05-01-preview",
          "dependsOn": [
            "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]"
          ],
          "properties": {
            "publisher": "Microsoft.Compute",
            "type": "CustomScriptExtension",
            "typeHandlerVersion": "1.4",
            "settings": {
              "fileUris": [
                "[concat(parameters('_artifactsLocation'),'/InstallVSTSAgent.ps1')]"
              ],
              "commandToExecute": "[concat('powershell.exe -ExecutionPolicy Unrestricted -Command .\\InstallVSTSAgent.ps1 -vstsAccount ', parameters('vstsAccount'), ' -personalAccessToken ', parameters('personalAccessToken'), ' -AgentName ', parameters('vstsAccount'), ' -PoolName ', parameters('poolName'), ' -runAsAutoLogon ', parameters('enableAutologon'), ' -vmAdminUserName ', parameters('vmAdminUserName'), ' -vmAdminPassword ', parameters('vmAdminPassword'))]"
            }
          }
        }
      ]

EDIT1

I've updated the template and moved the child resource out so that the child resource is at the same level as the parent. This section now looks like this:

{
  "name": "CustomScript",
  "type": "Microsoft.Compute/virtualMachines/extensions",
  "location": "[parameters('location')]",
  "apiVersion": "2015-05-01-preview",
  "dependsOn": [
    "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]"
  ],
  "copy": {
    "name": "customScriptGroup",
    "count": "[parameters('agentCount')]"
  },
  "properties": {
    "publisher": "Microsoft.Compute",
    "type": "CustomScriptExtension",
    "typeHandlerVersion": "1.4",
    "protectedSettings": {
      "fileUris": [
        "[concat(parameters('_artifactsLocation'),'/InstallVSTSAgent.ps1')]"
      ],
      "commandToExecute": "[concat('powershell.exe -ExecutionPolicy Unrestricted -Command .\\InstallVSTSAgent.ps1 -vstsAccount ', parameters('vstsAccount'), ' -personalAccessToken ', parameters('personalAccessToken'), ' -AgentName ', parameters('vstsAccount')[copyIndex(1)], ' -PoolName ', parameters('poolName'), ' -runAsAutoLogon ', parameters('enableAutologon'), ' -vmAdminUserName ', parameters('vmAdminUserName'), ' -vmAdminPassword ', parameters('vmAdminPassword'))]"
    }
  }
}

However, when I try and deploy I get this error:

Error: Code=InvalidTemplate; Message=Deployment template validation failed: The template resource 'CustomScript' for type 'Microsoft.Compute/virtualMachines/extensions' at line '247' and column '9' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name.

Mark Allison
  • 6,838
  • 33
  • 102
  • 151

2 Answers2

0

I believe what you are looking for is located here: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple

Where you can use the copyIndex() function to iterate in a loop to create multiple resources.

The above link has good examples and a clean way to do it but for your above template you will need to make some changes to the majority of your template if you want the naming convention to also be consistent with your NICs and such

Something like this should help you get going:

{
   "name" : "[concat(parameters('vmName'), copyIndex())]",
   "copy": {
      "name" : "vmCopy",
      "count": 10
   }
   ...
   ...
   ...
   "osProfile" : "[concat(parameters('vmName'), copyIndex())]"
   ...
   ...
}

The "copy" property here sets the name of the copy loop and the count it will iterate through. There are examples in the above link also of how this can be done.

Hope this helps!

Cheers, Lachie

Lachie White
  • 1,246
  • 2
  • 14
  • 21
  • Thanks, I had a look at the link you sent, and it seems I need to move the child resource to the same level as the parent. However it's still not working, please see EDIT1. Many thanks! – Mark Allison Jul 03 '18 at 08:33
  • for that error have a look at: https://stackoverflow.com/questions/26766882/azure-website-resource-template-error I had a similar error and this answer took care of it previously – Lachie White Jul 03 '18 at 08:46
  • are you attempting to build 10 VMs which is running 10 Agents or 10 vsts agents on a single VM? @MarkAllison – Lachie White Jul 03 '18 at 08:48
  • I have re-read your question and believe you are looking to have 10 agents on a single machine. then its can be done in JSON but is going to be messy. you would be much better editing the installvstsagent.ps1 script – Lachie White Jul 03 '18 at 09:03
  • I'm looking to install multiple agents on a single VM. I'll have a look at editing the script. thanks. – Mark Allison Jul 03 '18 at 09:59
  • for the Powershell script create a parameter of count, and use that to create a list of the 10 agent names, then loop through each agent name (in parallel if you wanted) – Lachie White Jul 03 '18 at 10:13
  • Lachie just found this lol https://github.com/Azure/azure-quickstart-templates/tree/master/201-vm-vsts-agent – Mark Allison Jul 03 '18 at 10:37
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/174241/discussion-between-lachie-white-and-mark-allison). – Lachie White Jul 03 '18 at 10:39
0

I have been able to use this script to install multiple agents on servers:

Get-ExecutionPolicy

Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser

for($i=0; $i -le 9;  $i++)
{
    $suffix=$i.ToString('00')
    $folder="vsts-agent-win-x64-2.144.2-$suffix"
    $agent="myagent-$suffix"

    "$PSScriptRoot\$folder"
    #note: folder needs to be copied for each instance
    #'vsts-agent-win-x64-2.144.2' is the folder after downloading and unzipping agent -manually.
    Copy-Item "$PSScriptRoot\vsts-agent-win-x64-2.144.2" "$PSScriptRoot\$folder" -Recurse

    cd $PSScriptRoot\$folder
 #.\config.cmd --unattended --url https://myaccount.visualstudio.com --auth pat --token myToken --pool 
#default --agent myAgent --runAsAutoLogon --windowsLogonAccount myDomain\myUserName 
#--windowsLogonPassword myPassword
    Write-Host "vsts-agent-win-x64-2.144.2-$suffix"

     .\config.cmd    --unattended `
                    --url "https://devops.my.org/org/" ` #(url of tfs)
                    --auth "pat" `
                    --token "u7s2mbna5v7heqzyfmz5ufrnvlektessebs7flfaf2ll4efzuj7q" `  (tfs token)
                    --pool "foiaModernization" `
                    --agent $agent `
                    --replace `
                    --acceptTeeEula `
                    --runAsService `
                    --windowsLogonAccount "xxx\yyy" `  #not sure if these lines are needed
                    --windowsLogonPassword "JJJJJlllll!!11" #not sure if these lines are 

}

jlo-gmail
  • 4,453
  • 3
  • 37
  • 64