JsonADDomainExtension和复制循环出错

时间:2019-06-11 07:13:47

标签: azure azure-resource-manager arm-template

我已经开发了ARM模板,它将并行构建多个VM。每台计算机都有一个OS磁盘和一个vNIC。我可以使用PowerShell部署ARM模板,也可以使用Azure门户的“部署自定义模板”功能上载ARM模板并进行部署。

但是我似乎不太能正确地使用复制循环在JsonADDomainExtension中添加语法,以便所有计算机都以相同的模板添加到我的域中。

目前,我所有的资源都在一个资源组中。我已经预先部署了带有子网和存储帐户的vNET。

下面是可同时部署多台计算机的ARM模板。

{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters":
    {
    "adminUsername":
        {
        "type": "string",
        "metadata": {"description": "Administrator username for the Virtual Machine."}
        },
    "adminPassword":
         {
        "type": "securestring",
        "metadata": {"description": "Password for the Virtual Machine.Should contain any 3 of: 1 Lower Case, 1 Upper Case, 1 Number and 1 Special character."}
        },
    "numberOfInstances":
        {
        "type": "int",
        "defaultValue": 3,
        "minValue": 2,
        "maxValue": 5,
        "metadata": {"description": "Number of VMs to deploy, limit 5 since this sample is using a single storage account."}
        },
    "StartOfCount":
        {
        "type": "int",
        "defaultValue": 1,
        "metadata": {"description": "Number that you want to start the machine name numbering from, EG to create 5 VMs with the name starting at 045 (W2016SRV-045-vm) you would enter 45 here, or to start at 1 just enter 1 here, this wil give you a machine name like 'W2016SRV-001-vm'."}
        },
    "vmNamePrefix": 
        {
            "type": "string",
            "defaultValue": "W2016SRV-",
            "maxLength": 9,
            "metadata": {"description": "The VM name prefix maximum 9 characters. This allows for three digits in the name and trailing '-vm'. EG: 'W2016SRV-045-vm'."}
            },
    "vmSize": 
        {
        "type": "string",
        "defaultValue": "Standard_B2ms",
        "metadata": 
            {
            "description": "The size(T-shirt) for the VM. (Standard_D8s_v3)",
            "SNC::Parameter::Metadata": {"referenceType": "Microsoft.Compute/virtualMachines/vmSize"}
            }
        },
    "vmLocation": 
        {
        "type": "string",
        "defaultValue": "AustraliaSoutheast",
        "metadata": 
            {
            "description": "Location or datacenter where the VM will be placed.",
            "SNC::Parameter::Metadata": {"referenceType": "Microsoft.Azure/region"}
            }
        },
    "domainToJoin": 
        {
        "type": "string",
        "metadata": {"description": "The FQDN of the AD domain"}
        },
    "domainUsername": 
        {
        "type": "string",
        "metadata": {"description": "Username of the account on the domain"}
        },
    "domainPassword": 
        {
        "type": "securestring",
        "metadata": {"description": "Password of the account on the domain"}
        },
    "ouPath": 
        {
        "type": "string",
        "metadata": {"description": "Specifies an organizational unit (OU) for the domain account. Enter the full distinguished name of the OU in quotation marks. Example: 'OU=testOU; DC=domain; DC=Domain; DC=com"}
        },
    "sizeOfDiskInGB": 
        {
        "type": "int",
        "defaultValue": 200,
        "metadata": {"description": "The disk size for the OS drive in the VM, in GBs. Default Value is 500"}
        },
    "existingBootDiagStorageResourceGroup": 
        {
        "type": "string",
        "metadata": {"description": "Storage account resource group name where boot diagnistics will be stored"}
        },
    "existingBootDiagStorageName": 
        {
        "type": "string",
        "metadata": 
            {
            "description": "Storage account name where boot diagnistics will be stored. It should be at the same location as the VM.",
            "SNC::Parameter::Metadata": {"referenceType": "Microsoft.Storage/storageAccounts"}
            }
        },
    "existingvNetResourceGroup": 
        {
        "type": "string",
        "metadata": 
            {
            "description": "Resource Group of the Existing Virtual Network.",
            "SNC::Parameter::Metadata": {"referenceType": "Microsoft.Resources/resourceGroups"}
            }
        },
    "existingvNetName": 
        {
        "type": "string",
        "metadata": 
            {
            "description": "Existing Virtual Network to connect to Network Interface to.It should be at the same location as the VM.",
            "SNC::Parameter::Metadata": {"referenceType": "Microsoft.Network/virtualNetworks"}
            }
        },
    "subnetName": 
        {
        "type": "string",
        "metadata": 
            {
            "description": "The Subnet for the VM.",
            "SNC::Parameter::Metadata": {"referenceType": "Microsoft.Network/subNets"}
            }
        }
    },
"variables": 
    {
    "storageAccountType": "Standard_LRS",
    "vnetID": "[resourceId(parameters('existingvNetResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('existingvNetName'))]",
    "subnetRef": "[concat(variables('vnetID'),'/subnets/', parameters('subnetName'))]",
    "StartOfCountString": "[String(Parameters('StartOfCount'))]"
    },
"resources": 
    [
        {
        "apiVersion": "[providers('Microsoft.Network','networkInterfaces').apiVersions[0]]",
        "type": "Microsoft.Network/networkInterfaces",
        "name": "[concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'), '-vm-vNic')]",
        "location": "[parameters('vmLocation')]",
        "copy": {
            "name": "nicLoop",
            "count": "[parameters('numberOfInstances')]"
            },
        "properties": 
            {
            "ipConfigurations": 
                [
                    {
                    "name": "Prod",
                    "properties": 
                        {
                        "privateIPAllocationMethod": "Dynamic",
                        "subnet": {"id": "[variables('subnetRef')]"}
                        }
                    }
                ]
            }
        },
        {
        "apiVersion": "[providers('Microsoft.Compute','virtualMachines').apiVersions[0]]",
        "type": "Microsoft.Compute/virtualMachines",
        "name": "[concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'), '-vm')]",
        "location": "[parameters('vmLocation')]",
        "copy": {
            "name": "vmLoop",
            "count": "[parameters('numberOfInstances')]"
            },
        "dependsOn": ["nicLoop"],
        "tags": 
            {
            "Project": "***"
            },
        "properties": 
            {
            "hardwareProfile": {"vmSize": "[parameters('vmSize')]"},
            "osProfile": 
                {
                "computerName": "[concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'), '-vm')]",
                "adminUsername": "[parameters('adminUsername')]",
                "adminPassword": "[parameters('adminPassword')]",
                "windowsConfiguration": {"enableAutomaticUpdates": false}
                },
            "storageProfile": 
                {
                "imageReference": {
                    "id": "/subscriptions/***/resourceGroups/***/providers/Microsoft.Compute/images/***"
                },
                "osDisk": 
                    {
                    "name": "[concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'), '-vm-osDisk')]",
                    "createOption": "FromImage",
                    "diskSizeGB": "[parameters('sizeOfDiskInGB')]",
                    "caching": "ReadWrite",
                    "managedDisk": {"storageAccountType": "[variables('storageAccountType')]"}
                    }
                },
            "networkProfile": {"networkInterfaces": [{"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'), '-vm-vNic'))]"}]},
            "diagnosticsProfile": 
                {
                "bootDiagnostics": 
                    {
                    "enabled": true,
                    "storageUri": "[reference(resourceId(parameters('existingBootDiagStorageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('existingBootDiagStorageName')), '2015-06-15').primaryEndpoints['blob']]"
                    }
                }
            }
        }
    ]
}

但是,如果我将其添加到底部的资源中,那么它将无法正常工作。

{
    "apiVersion": "2016-03-30",
    "type": "Microsoft.Compute/virtualMachines/extensions",
    "name": "[concat(parameters('vmNamePrefix'), padLeft(copyIndex(variables('StartOfCountString')),3, '0'), '/JoinDomain')]",
    "location": "[resourceGroup().location]",
    "copy": {
        "name": "DomainJoinLoop",
        "count": "[parameters('numberOfInstances')]"
    },
    "dependsOn": "[concat('Microsoft.Compute/virtualMachines/', concat(parameters('vmNamePrefix'), padLeft(copyIndex(variables('StartOfCountString')),3, '0')))]",
    "properties": {
        "publisher": "Microsoft.Compute",
        "type": "JsonADDomainExtension",
        "typeHandlerVersion": "1.3",
        "autoUpgradeMinorVersion": true,
        "settings": {
            "Name": "[parameters('domainToJoin')]",
            "User": "[concat(parameters('domainToJoin'), '\\', parameters('domainUsername'))]",
            "OUPath": "[parameters('ouPath')]",
            "Restart": "true",
            "Options": "3"
        },
        "protectedsettings": {
            "Password": "[parameters('domainPassword')]"
        }
    }
}

在代码的copyIndex部分中,我尝试了变量和参数来设置copyIndex的偏移量。我也尝试过硬编码。我不断收到这样的错误。

  

{“ telemetryId”:“ 649e0a7f-2c22-41f9-bede-c13618f5053a”,   “ bladeInstanceId”:“ Blade_b45c7efadff74340820345aa2e9d76c1_26_0”,   “ galleryItemId”:“ Microsoft.Template”,“ createBlade”:“ DeployToAzure”,   “ code”:“ InvalidRequestContent”,“ message”:“请求内容为   无效,无法反序列化:'转换值时出错   \“ [concat('Microsoft.Compute / virtualMachines /',   concat(参数('vmNamePrefix'),   padLeft(copyIndex(variables('StartOfCountString')),3,'0'))))\“至   输入“ System.String []”。路径   'properties.template.resources [1] .resources [0] .dependsOn',第259行,   位置171。'。“}

我要为复制索引设置偏移量的原因是,我可以构建10台机器,例如W2016SRV-001、002,... 010,然后再构建更多从011,012开始的机器, 013,等等。

还有其他解决方法,但我确实希望能够在ARM模板中做到这一点,但我在进行了广泛的搜索之后仍不知道为什么不可行。

............................................... ................................

好的,因此在按照@ 4c74356b41的建议编辑模板后,当我尝试通过门户部署模板时,我现在遇到了一个全新的错误。

{"telemetryId":"649e0a7f-2c22-41f9-bede-c13618f5053a",
"bladeInstanceId":"Blade_b45c7efadff74340820345aa2e9d76c1_26_0",
"galleryItemId":"Microsoft.Template","createBlade":"DeployToAzure",
"code":"InvalidTemplate",
"message":"Deployment template validation failed: 'The template resource 
'[concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'),
'-vm/JoinDomain')]' 
at line '250' column '13' is not valid. Copying nested resources is not supported. 
Please see https://aka.ms/arm-copy/#looping-on-a-nested-resource for usage details.'."}

因此,按照错误消息中的链接进行操作,然后阅读更多内容……我需要做的是将Domain Join Extension作为VM的子级删除,并将其作为顶级资源。哇,它奏效了。

所以现在我的ARM模板的结尾看起来像这样。

            *** VM bits are here ***
                }
            }
        }, <-- end of the VM bits.
        {
        "apiVersion": "2016-03-30",
        "type": "Microsoft.Compute/virtualMachines/extensions",
        "name": "[concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'), '-vm/JoinDomain')]",
        "location": "[resourceGroup().location]",
        "copy": {
            "name": "DomainJoinLoop",
            "count": "[parameters('numberOfInstances')]"
            },
        "dependsOn": [ "vmLoop" ],
        "properties": 
            {
            "publisher": "Microsoft.Compute",
            "type": "JsonADDomainExtension",
            "typeHandlerVersion": "1.3",
            "autoUpgradeMinorVersion": true,
            "settings":
                {
                "Name": "[parameters('domainToJoin')]",
                "User": "[concat(parameters('domainToJoin'), '\\', parameters('domainUsername'))]",
                "OUPath": "[parameters('ouPath')]",
                "Restart": "true",
                "Options": "3"
                },
            "protectedsettings": {"Password": "[parameters('domainPassword')]"}
            }
        }

    ],
"outputs":
    {}
}

并行部署的多个VM都已毫无问题地加入了域。

所以,我的经验教训是这些,我希望它们将来能对其他人有所帮助。

  1. 您不能在子级资源上使用copyIndex。
  2. 确保您正确命名DomainJoin扩展名。

1 个答案:

答案 0 :(得分:0)

比较您的虚拟机名称和扩展名:

concat(parameters('vmNamePrefix'), padLeft(copyIndex(parameters('StartOfCount')),3, '0'), '-vm')
concat(parameters('vmNamePrefix'), padLeft(copyIndex(variables('StartOfCountString')),3, '0'), '/JoinDomain')

除了您使用不必要的变量之外,您还缺少-vm。扩展名的格式必须为parent_name/extension_name,否则它将不知道此扩展属于哪个父资源(必须始终属于某个虚拟机)。

您的dependsOn也错了,您可以将其简化为:

"dependsOn": [ "vmLoop" ]