Azure Resource Manager テンプレートを使う複数のパラメーターをまとめてデプロイする PowerShell スクリプト

タイトルが何言ってるのかよく分かりませんが要するに VM とか１個ずつじゃなくてまとめてデプロイしたいってことです。

環境

- Windows 10 Enterprise
- PowerShell 5.1

使い方

- １つだけデプロイする場合
    - deploy.ps1 と template.json と parameters.json を同一フォルダーに配置して deploy.ps1 を実行
- 複数デプロイする場合
    - deploy.ps1 と template.json を配置したフォルダーに parameters フォルダーを作成して、parameters フォルダー配下にデプロイしたいパラメーターを記述した json ファイルを配置
    - または、deploy.ps1 と template.json を配置したフォルダーにパラメーターを記載した json ファイルを複数記載して、 -parametersFilePaths で指定

# デプロイ用スクリプト

deploy.ps1 はこんな感じになります。

```ps1:deploy.ps1
<#
 .SYNOPSIS
    Deploys a template to Azure

 .DESCRIPTION
    Deploys an Azure Resource Manager template

 .PARAMETER subscriptionId
    The subscription id where the template will be deployed.

 .PARAMETER resourceGroupName
    The resource group where the template will be deployed. Can be the name of an existing or a new resource group.

 .PARAMETER resourceGroupLocation
    Optional, a resource group location. If specified, will try to create a new resource group in this location. If not specified, assumes resource group is existing.

 .PARAMETER deploymentName
    The deployment name.

 .PARAMETER templateFilePath
    Optional, path to the template file. Defaults to template.json.

 .PARAMETER parametersFilePaths
    Optional, path to the parameters files. Defaults to parameters.json. If file is not found, will prompt for parameter values based on template.
 
 .PARAMETER parametersDirectoryPath
    Optional, path to the directory which has parameters files. Defaults to parameters.
#>

param(
 [Parameter(Mandatory=$True)]
 [string]
 $subscriptionId,

 [Parameter(Mandatory=$True)]
 [string]
 $resourceGroupName,

 [string]
 $resourceGroupLocation,

 [Parameter(Mandatory=$True)]
 [string]
 $deploymentName,

 [string]
 $templateFilePath = "template.json",

 [string[]]
 $parametersFilePaths = "parameters.json",

 [string]
 $parametersDirectoryPath = "parameters"
)

<#
.SYNOPSIS
    Registers RPs
#>
Function RegisterRP {
    Param(
        [string]$ResourceProviderNamespace
    )

    Write-Host "Registering resource provider '$ResourceProviderNamespace'";
    Register-AzureRmResourceProvider -ProviderNamespace $ResourceProviderNamespace;
}

#******************************************************************************
# Script body
# Execution begins here
#******************************************************************************
$ErrorActionPreference = "Stop"

# sign in
try {
    Get-AzureRmSubscription | Out-Null
}
catch {
    Write-Host "Logging in...";
    Login-AzureRmAccount;
}

# select subscription
Write-Host "Selecting subscription '$subscriptionId'";
Select-AzureRmSubscription -SubscriptionID $subscriptionId;

# Register RPs
$resourceProviders = @("microsoft.compute","microsoft.network");
if($resourceProviders.length) {
    Write-Host "Registering resource providers"
    foreach($resourceProvider in $resourceProviders) {
        RegisterRP($resourceProvider);
    }
}

#Create or check for existing resource group
$resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
if(!$resourceGroup)
{
    Write-Host "Resource group '$resourceGroupName' does not exist. To create a new resource group, please enter a location.";
    if(!$resourceGroupLocation) {
        $resourceGroupLocation = Read-Host "resourceGroupLocation";
    }
    Write-Host "Creating resource group '$resourceGroupName' in location '$resourceGroupLocation'";
    New-AzureRmResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation
}
else{
    Write-Host "Using existing resource group '$resourceGroupName'";
}

# Check for directory

if (Test-Path $parametersDirectoryPath) {
    if (get-childitem $parametersDirectoryPath -Filter *.json) {
        $parametersFilePaths = (get-childitem $parametersDirectoryPath -Filter *.json).fullname
    }
}

# Start the deployment
Write-Host "Starting deployment...";

foreach ($parametersFilePath in $parametersFilePaths) {
    if(Test-Path $parametersFilePath) {
        New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $templateFilePath -TemplateParameterFile $parametersFilePath;
    } else {
        New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $templateFilePath;
    }
}
```

# テンプレート

別の記事 http://qiita.com/yuki451/items/9a6bfc0e544cdcc32788 で作った template.json を使って試してみます。

```json:template.json
{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "type": "string"
        },
        "virtualMachineName": {
            "type": "string"
        },
        "storageAccountType": {
            "type": "string"
        },
        "virtualMachineSize": {
            "type": "string"
        },
        "virtualMachinePublisher": {
            "type": "string"
        },
        "virtualMachineOffer": {
            "type": "string"
        },
        "virtualMachineSku": {
            "type": "string"
        },
        "adminUsername": {
            "type": "string"
        },
        "adminPassword": {
            "type": "securestring"
        },
        "virtualNetworkName": {
            "type": "string"
        },
        "addressPrefix": {
            "type": "string"
        },
        "subnetName": {
            "type": "string"
        },
        "subnetPrefix": {
            "type": "string"
        },
        "networkInterfaceName": {
            "type": "string"
        },
        "privateIpAddress": {
            "type": "string"
        },
        "publicIpAddressName": {
            "type": "string"
        },
        "publicIpAddressType": {
            "type": "string"
        },
        "networkSecurityGroupName": {
            "type": "string"
        }
    },
    "variables": {
        "vnetId": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]",
        "subnetRef": "[concat(variables('vnetId'), '/subnets/', parameters('subnetName'))]"
    },
    "resources": [
        {
            "name": "[parameters('virtualMachineName')]",
            "type": "Microsoft.Compute/virtualMachines",
            "apiVersion": "2016-04-30-preview",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[concat('Microsoft.Network/networkInterfaces/', parameters('networkInterfaceName'))]"
            ],
            "properties": {
                "osProfile": {
                    "computerName": "[parameters('virtualMachineName')]",
                    "adminUsername": "[parameters('adminUsername')]",
                    "adminPassword": "[parameters('adminPassword')]",
                    "windowsConfiguration": {
                        "provisionVmAgent": "true"
                    }
                },
                "hardwareProfile": {
                    "vmSize": "[parameters('virtualMachineSize')]"
                },
                "storageProfile": {
                    "imageReference": {
                        "publisher": "[parameters('virtualMachinePublisher')]",
                        "offer": "[parameters('virtualMachineOffer')]",
                        "sku": "[parameters('virtualMachineSku')]",
                        "version": "latest"
                    },
                    "osDisk": {
                        "name": "[parameters('virtualMachineName')]",
                        "createOption": "fromImage",
                        "managedDisk": {
                            "storageAccountType": "[parameters('storageAccountType')]"
                        }
                    },
                    "dataDisks": []
                },
                "networkProfile": {
                    "networkInterfaces": [
                        {
                            "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaceName'))]"
                        }
                    ]
                }
            }
        },
        {
            "name": "[parameters('virtualNetworkName')]",
            "type": "Microsoft.Network/virtualNetworks",
            "apiVersion": "2016-09-01",
            "location": "[parameters('location')]",
            "properties": {
                "addressSpace": {
                    "addressPrefixes": [
                        "[parameters('addressPrefix')]"
                    ]
                },
                "subnets": [
                    {
                        "name": "[parameters('subnetName')]",
                        "properties": {
                            "addressPrefix": "[parameters('subnetPrefix')]"
                        }
                    }
                ]
            }
        },
        {
            "name": "[parameters('networkInterfaceName')]",
            "type": "Microsoft.Network/networkInterfaces",
            "apiVersion": "2016-09-01",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]",
                "[concat('Microsoft.Network/publicIpAddresses/', parameters('publicIpAddressName'))]",
                "[concat('Microsoft.Network/networkSecurityGroups/', parameters('networkSecurityGroupName'))]"
            ],
            "properties": {
                "ipConfigurations": [
                    {
                        "name": "ipconfig1",
                        "properties": {
                            "subnet": {
                                "id": "[variables('subnetRef')]"
                            },
                            "privateIPAllocationMethod": "Static",
                            "privateIPAddress": "[parameters('privateIpAddress')]",
                            "publicIpAddress": {
                                "id": "[resourceId('Microsoft.Network/publicIpAddresses', parameters('publicIpAddressName'))]"
                            }
                        }
                    }
                ],
                "networkSecurityGroup": {
                    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]"
                }
            }
        },
        {
            "name": "[parameters('publicIpAddressName')]",
            "type": "Microsoft.Network/publicIpAddresses",
            "apiVersion": "2016-09-01",
            "location": "[parameters('location')]",
            "properties": {
                "publicIpAllocationMethod": "[parameters('publicIpAddressType')]"
            }
        },
        {
            "name": "[parameters('networkSecurityGroupName')]",
            "type": "Microsoft.Network/networkSecurityGroups",
            "apiVersion": "2016-09-01",
            "location": "[parameters('location')]",
            "properties": {
                "securityRules": [
                    {
                        "name": "default-allow-rdp",
                        "properties": {
                            "priority": 1000,
                            "sourceAddressPrefix": "*",
                            "protocol": "TCP",
                            "destinationPortRange": "3389",
                            "access": "Allow",
                            "direction": "Inbound",
                            "sourcePortRange": "*",
                            "destinationAddressPrefix": "*"
                        }
                    }
                ]
            }
        },
        {
            "name": "[concat('shutdown-computevm-', parameters('virtualMachineName'))]",
            "type": "Microsoft.DevTestLab/schedules",
            "apiVersion": "2016-05-15",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[concat('Microsoft.Compute/virtualMachines/', parameters('virtualMachineName'))]"
            ],
            "properties":{
                "status": "Enabled",
                "taskType": "ComputeVmShutdownTask",
                "dailyRecurrence":{
                    "time": "0200"
                },
                "timeZoneId": "Tokyo Standard Time",
                "notificationSettings":{
                    "status": "Disabled"
                },
                "targetResourceID": "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]"
            }
        }
    ],
    "outputs": {
        "adminUsername": {
            "type": "string",
            "value": "[parameters('adminUsername')]"
        }
    }
}
```

# パラメーター

パラメーターファイルは２つ（web-parameters.json と db-parameters.json）用意してみます。

```json:web-parameters.json
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "value": "japaneast"
        },
        "virtualMachineName": {
            "value": "web"
        },
        "storageAccountType": {
            "value": "Premium_LRS"
        },
        "virtualMachineSize": {
            "value": "Standard_DS1_v2"
        },
        "virtualMachinePublisher": {
            "value": "MicrosoftWindowsServer"
        },
        "virtualMachineOffer": {
            "value": "WindowsServer"
        },
        "virtualMachineSku": {
            "value": "2016-Datacenter"
        },
        "adminUsername": {
            "value": "CloudAdmin"
        },
        "adminPassword": {
            "value": "P@ssw0rd1234"
        },
        "virtualNetworkName": {
            "value": "vnet"
        },
        "addressPrefix": {
            "value": "10.0.0.0/16"
        },
        "subnetName": {
            "value": "default"
        },
        "subnetPrefix": {
            "value": "10.0.0.0/24"
        },
        "networkInterfaceName": {
            "value": "web-nic"
        },
        "privateIpAddress": {
            "value": "10.0.0.11"
        },
        "publicIpAddressName": {
            "value": "web-ip"
        },
        "publicIpAddressType": {
            "value": "Dynamic"
        },
        "networkSecurityGroupName": {
            "value": "web-nsg"
        }
    }
}
```

```json:db-parameters.json
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "value": "japaneast"
        },
        "virtualMachineName": {
            "value": "db"
        },
        "storageAccountType": {
            "value": "Premium_LRS"
        },
        "virtualMachineSize": {
            "value": "Standard_DS1_v2"
        },
        "virtualMachinePublisher": {
            "value": "MicrosoftWindowsServer"
        },
        "virtualMachineOffer": {
            "value": "WindowsServer"
        },
        "virtualMachineSku": {
            "value": "2016-Datacenter"
        },
        "adminUsername": {
            "value": "CloudAdmin"
        },
        "adminPassword": {
            "value": "P@ssw0rd1234"
        },
        "virtualNetworkName": {
            "value": "vnet"
        },
        "addressPrefix": {
            "value": "10.0.0.0/16"
        },
        "subnetName": {
            "value": "default"
        },
        "subnetPrefix": {
            "value": "10.0.0.0/24"
        },
        "networkInterfaceName": {
            "value": "db-nic"
        },
        "privateIpAddress": {
            "value": "10.0.0.12"
        },
        "publicIpAddressName": {
            "value": "db-ip"
        },
        "publicIpAddressType": {
            "value": "Dynamic"
        },
        "networkSecurityGroupName": {
            "value": "db-nsg"
        }
    }
}
```

各ファイルを以下のように配置します。

- deploy.ps1
- template.json
- parameters（フォルダー）
    - db-parameters.json
    - web-parameters.json

スクリプトを実行すると、仮想マシン web と db が順番にデプロイされました。

```
.\deploy.ps1 -subscriptionId <subscriptionID> -resourceGroupName <resourceGroupName> -deploymentName <deploymentName>
```