Skip to main content

Deploy with ARM templates an Azure DevTest Lab environment

Within the company I work for we use Azure DevTest Labs already for a year to host our personal development computer and the BizTalk CI machines we need. We are planning to host also our development and test environments in Lab environments. At the moment we configure the lab environments manually.

I invested some time to write ARM templates to deploy Azure DevTest Labs within 5 minutes based on Azure DevOps CI/CD pipelines. In the process of writing these scripts I learned a lot. For example that the Azure documentation is not always up to date and that includes also tooling like Azure Resource Explorer. Based on querying the REST API with Postman I found the missing pieces for deploying a DevTest Lab environment based on nested ARM templates.

In this post I will document the nested ARM template I created the last few days.

Lab

With the first template you can create the lab environment itself and configure the following parts of the environment
  • Lab settings; like the storage which the lab environment uses and if premium data disks are allowed.
  • Internal support; information for the internal support link.
  • Lab settings; if the lab users have read or contributor rights to the resource group.
  • Lab announcement; information which is displayed to the users on the lab overview page.
{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "labName": {
            "type": "string",
            "defaultValue": "Sandbox",
            "metadata": {
                "description": "The name of the lab."
            }
        },
        "labStorageType": {
            "type": "string",
            "defaultValue": "Premium",
            "allowedValues": [
                "Premium",
                "Standard"
            ],
            "metadata": {
                "description": "Type of storage used by the lab. It can be either Premium or Standard. Default is Premium."
            }
        },
        "premiumDataDiskStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of premium data disks."
            }
        },
        "environmentPermission": {
            "type": "string",
            "defaultValue": "Reader",
            "allowedValues": [
                "Reader",
                "Contributor"
            ],
            "metadata": {
                "description": "Give the lab users read or contributor rights for other resources in the lab resource group."
            }
        },
        "supportStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable showing the support markdown."
            }
        },
        "supportMarkdown": {
            "type": "string",
            "defaultValue": "Contact the service desk when you need support for the lab environment.",
            "metadata": {
                "description": "The mark down contents of the support message (maximum 4096 characters)."
            }
        },
        "announcementStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable showing the announcement markdown."
            }
        },
        "announcementTitle": {
            "type": "string",
            "defaultValue": "Planned maintenance",
            "metadata": {
                "description": "The title for the announcement."
            }
        },
        "announcementMarkdown": {
            "type": "string",
            "defaultValue": "Today there will be planned maintenance on the Lab Management environment.",
            "metadata": {
                "description": "The markdown contents of the announcement (maximum 4096 characters)."
            }
        },
        "announcementExpiration": {
            "type": "string",
            "defaultValue": "2025-11-30T14:30:00+01:00",
            "metadata": {
                "description": "The date/time when the announcement has to expire."
            }
        },
        "tagsCostCenter": {
            "type": "string",
            "defaultValue": "L7330",
            "metadata": {
                "description": "The name of the cost center to bill."
            }
        },
        "tagsEnvironment": {
            "type": "string",
            "defaultValue": "non-prod",
            "allowedValues": [
                "non-prod",
                "prod"
            ],
            "metadata": {
                "description": "Are the resources used for non production or production environments."
            }
        },
        "tagsOperationsTeam": {
            "type": "string",
            "defaultValue": "ICT",
            "metadata": {
                "description": "By which operations team are the resources maintained."
            }
        },
        "tagsPlatform": {
            "type": "string",
            "defaultValue": "DevTest Labs",
            "metadata": {
                "description": "What is the purpose of the resource. For example which application use them."
            }
        }
    },
    "resources": [
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[parameters('labName')]",
            "type": "Microsoft.DevTestLab/labs",
            "location": "[resourceGroup().location]",
            "tags": {
                "CostCenter": "[parameters('tagsCostCenter')]",
                "Environment": "[parameters('tagsEnvironment')]",
                "Platform": "[parameters('tagsPlatform')]",
                "OperationsTeam": "[parameters('tagsOperationsTeam')]"
            },
            "properties": {
                "labStorageType": "[parameters('labStorageType')]",
                "premiumDataDisks": "[parameters('premiumDataDiskStatus')]",
                "environmentPermission": "[parameters('environmentPermission')]",
                "support": {
                    "enabled": "[parameters('supportStatus')]",
                    "markdown": "[parameters('supportMarkdown')]"
                },
                "announcement": {
                    "enabled": "[parameters('announcementStatus')]",
                    "expirationDate": "[parameters('announcementExpiration')]",
                    "markdown": "[parameters('announcementMarkdown')]",
                    "title": "[parameters('announcementTitle')]"
                }
            }
        }
    ]
}

Schedules

With the schedules template you control the automatic shutdown settings and the general startup settings.
{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "labName": {
            "type": "string",
            "defaultValue": "Sandbox",
            "metadata": {
                "description": "The name of the lab."
            }
        },
        "timeZoneId": {
            "type": "string",
            "defaultValue": "W. Europe Standard Time",
            "metadata": {
                "description": "The time zone Id."
            }
        },
        "labVmShutDownTime": {
            "type": "string",
            "defaultValue": "19:00",
            "minLength": 4,
            "maxLength": 5,
            "metadata": {
                "description": "The time (relative to timeZoneId) at which the Lab VMs will be automatically shutdown (E.g. 17:30, 20:00, 09:00)."
            }
        },
        "labVmShutDownTimeStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the auto shutdown schedule."
            }
        },
        "labVmStartupTime": {
            "type": "string",
            "defaultValue": "07:00",
            "minLength": 4,
            "maxLength": 5,
            "metadata": {
                "description": "The time (relative to timeZoneId) at which the Lab VMs will be automatically started (E.g. 07:00)."
            }
        },
        "labVmStartupStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Allow virtual machines to be scheduled for automatic start."
            }
        },
        "labVmStartupWeeklyRecurrence": {
            "type": "array",
            "defaultValue": [
                "Monday",
                "Wednesday",
                "Friday"
            ],
            "metadata": {
                "description": "On which days of the week has the startup time schedule to be executed."
            }
        }
    },
    "resources": [
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'LabVmsShutdown')]",
            "type": "Microsoft.DevTestLab/labs/schedules",
            "location": "[resourceGroup().location]",
            "properties": {
                "status": "[parameters('labVmShutDownTimeStatus')]",
                "timeZoneId": "[parameters('timeZoneId')]",
                "dailyRecurrence": {
                    "time": "[string(parameters('labVmShutDownTime'))]"
                },
                "taskType": "LabVmsShutdownTask",
                "notificationSettings": {
                    "status": "Disabled",
                    "timeInMinutes": 30
                }
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'LabVmAutoStart')]",
            "type": "Microsoft.DevTestLab/labs/schedules",
            "location": "[resourceGroup().location]",
            "properties": {
                "status": "[parameters('labVmStartupStatus')]",
                "timeZoneId": "[parameters('timeZoneId')]",
                "weeklyRecurrence": {
                    "weekdays": "[parameters('labVmStartupWeeklyRecurrence')]",
                    "time": "[string(parameters('labVmStartupTime'))]"
                },
                "taskType": "LabVmsStartupTask",
                "notificationSettings": {
                    "status": "Disabled",
                    "timeInMinutes": 0
                }
            }
        }
    ]
}

Policies

The policies template control all kinds of restrictions which control the amount of money your lab users can spent. This is also the template which cost the most research time to write because the REST API documentation is behind the actual situation.
  • Auto shutdown policy; Set the level of control that lab users have over their individual VM shutdown schedules. You can mandate different levels betweeen complete autonomy and a locked down schedule.
  • Allowed virtual machine sizes.
  • Number of virtual machines per user (including premium OS disk usage).
  • Number of virtual machines per lab (including premium OS disk usage).
  • Allowed gallery images; option to restrict which images are useable within the lab environment.
  • Allowed environment templates; option to restrict which ARM templates can be used within the lab environment.
{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "labName": {
            "type": "string",
            "defaultValue": "Sandbox",
            "metadata": {
                "description": "The name of the lab."
            }
        },
        "scheduleEditPermission": {
            "type": "string",
            "defaultValue": "\"None\"",
            "allowedValues": [
                "\"None\",\"Modify\",\"OptOut\"",
                "\"None\",\"Modify\"",
                "\"None\""
            ],
            "metadata": {
                "description": "Set the level of control that lab users have over their individual VM shutdown schedules."
            }
        },
        "maxAllowedVmsPerUser": {
            "type": "int",
            "defaultValue": 1,
            "metadata": {
                "description": "The maximum number of VMs allowed per user."
            }
        },
        "maxAllowedVmsPerUserStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of VMs allowed per user policy."
            }
        },
        "maxAllowedPremiumVmsPerUser": {
            "type": "int",
            "defaultValue": 1,
            "metadata": {
                "description": "The maximum number of premium VMs allowed per user."
            }
        },
        "maxAllowedPremiumVmsPerUserStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of premium VMs allowed per user policy."
            }
        },
        "maxAllowedVmsPerLab": {
            "type": "int",
            "defaultValue": 100,
            "metadata": {
                "description": "The maximum number of VMs allowed per lab."
            }
        },
        "maxAllowedVmsPerLabStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of VMs allowed per lab policy."
            }
        },
        "maxAllowedPremiumVmsPerLab": {
            "type": "int",
            "defaultValue": 100,
            "metadata": {
                "description": "The maximum number of premium VMs allowed per lab."
            }
        },
        "maxAllowedPremiumVmsPerLabStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of premium VMs allowed per lab policy."
            }
        },
        "allowedVmSizes": {
            "type": "string",
            "defaultValue": "\"Standard_A5\", \"Standard_A3\", \"Standard_A2\"",
            "metadata": {
                "description": "A comma-separated list of VM sizes that are allowed in the lab."
            }
        },
        "allowedVmSizesStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable VM sizes allowed per lab policy."
            }
        },
        "allowedGalleryImages": {
            "type": "string",
            "defaultValue": "\"{\\\"offer\\\":\\\"CentOS\\\",\\\"publisher\\\":\\\"OpenLogic\\\",\\\"sku\\\":\\\"7.2\\\",\\\"osType\\\":\\\"Linux\\\",\\\"version\\\":\\\"latest\\\"}\",\"{\\\"offer\\\":\\\"Oracle-Linux\\\",\\\"publisher\\\":\\\"Oracle\\\",\\\"sku\\\":\\\"7.2\\\",\\\"osType\\\":\\\"Linux\\\",\\\"version\\\":\\\"latest\\\"}\",\"{\\\"offer\\\":\\\"SQL2016-WS2012R2\\\",\\\"publisher\\\":\\\"MicrosoftSQLServer\\\",\\\"sku\\\":\\\"Enterprise\\\",\\\"osType\\\":\\\"Windows\\\",\\\"version\\\":\\\"latest\\\"}\"",
            "metadata": {
                "description": "A list of gallery images that are allowed in the lab."
            }
        },
        "allowedGalleryImagesStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the allowed gallery images policy."
            }
        },
        "allowedEnvironmentTemplates": {
            "type": "string",
            "defaultValue": "\"{\\\"armTemplateName\\\":\\\"WebApp-SQL\\\",\\\"repositorySourceName\\\":\\\"Public Environment Repo\\\"}\",\"{\\\"armTemplateName\\\":\\\"WebApp\\\",\\\"repositorySourceName\\\":\\\"Public Environment Repo\\\"}\"",
            "metadata": {
                "description": "A list of environment templates that are allowed in the lab."
            }
        },
        "allowedEnvironmentTemplatesStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the allowed environment templates policy."
            }
        }
    },
    "resources": [
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/ScheduleEditPermission')]",
            "type": "Microsoft.DevTestLab/labs/policysets/policies",
            "location": "[resourceGroup().location]",
            "properties": {
                "description": "Set the level of control that lab users have over their individual VM shutdown schedules.",
                "factName": "ScheduleEditPermission",
                "threshold": "[concat('[', trim(parameters('scheduleEditPermission')), ']')]",
                "evaluatorType": "AllowedValuesPolicy",
                "status": "Enabled"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/MaxVmsAllowedPerUser')]",
            "type": "Microsoft.DevTestLab/labs/policysets/policies",
            "location": "[resourceGroup().location]",
            "properties": {
                "description": "Limit the number of virtual machines per user",
                "factName": "UserOwnedLabVmCount",
                "threshold": "[string(parameters('maxAllowedVmsPerUser'))]",
                "evaluatorType": "MaxValuePolicy",
                "status": "[parameters('maxAllowedVmsPerUserStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/MaxPremiumVmsAllowedPerUser')]",
            "type": "Microsoft.DevTestLab/labs/policysets/policies",
            "location": "[resourceGroup().location]",
            "properties": {
                "description": "Limit the number of premium virtual machines per user",
                "factName": "UserOwnedLabPremiumVmCount",
                "threshold": "[string(parameters('maxAllowedPremiumVmsPerUser'))]",
                "evaluatorType": "MaxValuePolicy",
                "status": "[parameters('maxAllowedPremiumVmsPerUserStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/MaxVmsAllowedPerLab')]",
            "type": "Microsoft.DevTestLab/labs/policysets/policies",
            "location": "[resourceGroup().location]",
            "properties": {
                "description": "Limit the total number of virtual machines in the lab",
                "factName": "LabVmCount",
                "threshold": "[string(parameters('maxAllowedVmsPerLab'))]",
                "evaluatorType": "MaxValuePolicy",
                "status": "[parameters('maxAllowedVmsPerLabStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/MaxPremiumVmsAllowedPerLab')]",
            "type": "Microsoft.DevTestLab/labs/policysets/policies",
            "location": "[resourceGroup().location]",
            "properties": {
                "description": "Limit the total number of premium virtual machines in the lab",
                "factName": "UserOwnedLabPremiumVmCount",
                "threshold": "[string(parameters('maxAllowedPremiumVmsPerLab'))]",
                "evaluatorType": "MaxValuePolicy",
                "status": "[parameters('maxAllowedPremiumVmsPerLabStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/AllowedVmSizesInLab')]",
            "type": "Microsoft.DevTestLab/labs/policysets/policies",
            "location": "[resourceGroup().location]",
            "properties": {
                "description": "Limit the allowed virtual machine sizes in the lab",
                "factName": "LabVmSize",
                "threshold": "[concat('[', trim(parameters('allowedVmSizes')), ']')]",
                "evaluatorType": "AllowedValuesPolicy",
                "status": "[parameters('allowedVmSizesStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/GalleryImage')]",
            "type": "Microsoft.DevTestLab/labs/policySets/policies",
            "properties": {
                "description": "Limit the type of gallery images that can be used",
                "factName": "GalleryImage",
                "threshold": "[concat('[', trim(parameters('allowedGalleryImages')), ']')]",
                "evaluatorType": "AllowedValuesPolicy",
                "status": "[parameters('allowedGalleryImagesStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'default/EnvironmentTemplate')]",
            "type": "Microsoft.DevTestLab/labs/policySets/policies",
            "properties": {
                "description": "Limit the type of environment templates that can be used",
                "factName": "EnvironmentTemplate",
                "threshold": "[concat('[', trim(parameters('allowedEnvironmentTemplates')), ']')]",
                "evaluatorType": "AllowedValuesPolicy",
                "status": "[parameters('allowedEnvironmentTemplatesStatus')]"
            }
        }
    ]
}

Artifact sources

With this template you control the usage of the public artifact and environment repo hosted by Microsoft. You can also add a private hosted artifact and environment repo based on GIT hosted by Azure DevOps or GitHub.
{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "labName": {
            "type": "string",
            "defaultValue": "Sandbox",
            "metadata": {
                "description": "The name of the lab."
            }
        },
        "publicArtifactRepoStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of public artifacts."
            }
        },
        "publicEnvironmentRepoStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of public environment templates."
            }
        },
        "privateRepoStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of private artifacts and environment templates."
            }
        },
        "privateRepoUri": {
            "type": "string",
            "defaultValue": "https://dev.azure.com/tenant-name/project-name/_git/repo-name",
            "metadata": {
                "description": "The artifact source's URI."
            }
        },
        "privateRepoFolderEnvironments": {
            "type": "string",
            "defaultValue": "environments/",
            "metadata": {
                "description": "The folder containing environment (Azure Resource Manager) templates."
            }
        },
        "privateRepoFolderArtifacts": {
            "type": "string",
            "defaultValue": "artifacts/",
            "metadata": {
                "description": "The folder containing artifacts."
            }
        },
        "privateRepoBranchRef": {
            "type": "string",
            "defaultValue": "master",
            "metadata": {
                "description": "The artifact source's branch reference."
            }
        },
        "privateRepoDisplayName": {
            "type": "string",
            "defaultValue": "Private Repo",
            "metadata": {
                "description": "The artifact source's display name."
            }
        },
        "privateRepoType": {
            "type": "string",
            "defaultValue": "VsoGit",
            "allowedValues": [
                "VsoGit",
                "GitHub"
            ],
            "metadata": {
                "description": "The artifact source's type."
            }
        },
        "privateRepoSecurityToken": {
            "type": "securestring",
            "defaultValue": "1111111111111111111111111111111111111111111111111111",
            "metadata": {
                "description": "The security token to authenticate to the artifact source."
            }
        }
    },
    "resources": [
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'Public Repo')]",
            "type": "Microsoft.DevTestLab/labs/artifactSources",
            "location": "[resourceGroup().location]",
            "properties": {
                "displayName": "Public Artifact Repo",
                "status": "[parameters('publicArtifactRepoStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'Public Environment Repo')]",
            "type": "Microsoft.DevTestLab/labs/artifactSources",
            "location": "[resourceGroup().location]",
            "properties": {
                "displayName": "Public Environment Repo",
                "status": "[parameters('publicEnvironmentRepoStatus')]"
            }
        },
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'Private Repo')]",
            "type": "Microsoft.DevTestLab/labs/artifactSources",
            "location": "[resourceGroup().location]",
            "properties": {
                "uri": "[parameters('privateRepoUri')]",
                "armTemplateFolderPath": "[parameters('privateRepoFolderEnvironments')]",
                "folderPath": "[parameters('privateRepoFolderArtifacts')]",
                "branchRef": "[parameters('privateRepoBranchRef')]",
                "displayName": "[parameters('privateRepoDisplayName')]",
                "securityToken": "[parameters('privateRepoSecurityToken')]",
                "sourceType": "[parameters('privateRepoType')]",
                "status": "[parameters('privateRepoStatus')]"
            }
        }
    ]
}

Virtual network

Defines the virtual network that is used by the lab environment.
{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "labName": {
            "type": "string",
            "defaultValue": "Sandbox",
            "metadata": {
                "description": "The name of the lab."
            }
        }
    },
    "resources": [
        {
            "apiVersion": "2018-10-15-preview",
            "name": "[concat(parameters('labName'), '/', 'Dtl', parameters('labName'))]",
            "type": "Microsoft.DevTestLab/labs/virtualNetworks",
            "location": "[resourceGroup().location]"
        }
    ]
}

Nested template

Orchestrates the deployment of all the templates.
{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "storageAccount": {
            "type": "string",
            "defaultValue": "https://devtestlabsci.blob.core.windows.net/templates/",
            "metadata": {
                "description": "The storage account which will be used for storing the ARM templates."
            }
        },
        "storageAccountSASToken": {
            "type": "string",
            "defaultValue": "",
            "metadata": {
                "description": "The SAS token to access the storage account."
            }
        },
        "labName": {
            "type": "string",
            "defaultValue": "Sandbox",
            "metadata": {
                "description": "The name of the lab."
            }
        },
        "labStorageType": {
            "type": "string",
            "defaultValue": "Premium",
            "allowedValues": [
                "Premium",
                "Standard"
            ],
            "metadata": {
                "description": "Type of storage used by the lab. It can be either Premium or Standard. Default is Premium."
            }
        },
        "premiumDataDiskStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of premium data disks."
            }
        },
        "environmentPermission": {
            "type": "string",
            "defaultValue": "Reader",
            "allowedValues": [
                "Reader",
                "Contributor"
            ],
            "metadata": {
                "description": "Give the lab users read or contributor rights for other resources in the lab resource group."
            }
        },
        "supportStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable showing the support markdown."
            }
        },
        "supportMarkdown": {
            "type": "string",
            "defaultValue": "Contact the service desk when you need support for the lab environment.",
            "metadata": {
                "description": "The mark down contents of the support message (maximum 4096 characters)."
            }
        },
        "announcementStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable showing the announcement markdown."
            }
        },
        "announcementTitle": {
            "type": "string",
            "defaultValue": "Planned maintenance",
            "metadata": {
                "description": "The title for the announcement."
            }
        },
        "announcementMarkdown": {
            "type": "string",
            "defaultValue": "Today there will be planned maintenance on the Lab Management environment.",
            "metadata": {
                "description": "The markdown contents of the announcement (maximum 4096 characters)."
            }
        },
        "announcementExpiration": {
            "type": "string",
            "defaultValue": "2025-11-30T14:30:00+01:00",
            "metadata": {
                "description": "The date/time when the announcement has to expire."
            }
        },
        "timeZoneId": {
            "type": "string",
            "defaultValue": "W. Europe Standard Time",
            "metadata": {
                "description": "The time zone Id."
            }
        },
        "labVmShutDownTime": {
            "type": "string",
            "defaultValue": "19:00",
            "minLength": 4,
            "maxLength": 5,
            "metadata": {
                "description": "The time (relative to timeZoneId) at which the Lab VMs will be automatically shutdown (E.g. 17:30, 20:00, 09:00)."
            }
        },
        "labVmShutDownTimeStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the auto shutdown schedule."
            }
        },
        "labVmStartupTime": {
            "type": "string",
            "defaultValue": "07:00",
            "minLength": 4,
            "maxLength": 5,
            "metadata": {
                "description": "The time (relative to timeZoneId) at which the Lab VMs will be automatically started (E.g. 07:00)."
            }
        },
        "labVmStartupStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Allow virtual machines to be scheduled for automatic start."
            }
        },
        "labVmStartupWeeklyRecurrence": {
            "type": "array",
            "defaultValue": [
                "Monday",
                "Wednesday",
                "Friday"
            ],
            "metadata": {
                "description": "On which days of the week has the startup time schedule to be executed."
            }
        },
        "scheduleEditPermission": {
            "type": "string",
            "defaultValue": "\"None\"",
            "allowedValues": [
                "\"None\",\"Modify\",\"OptOut\"",
                "\"None\",\"Modify\"",
                "\"None\""
            ],
            "metadata": {
                "description": "Set the level of control that lab users have over their individual VM shutdown schedules."
            }
        },
        "maxAllowedVmsPerUser": {
            "type": "int",
            "defaultValue": 1,
            "metadata": {
                "description": "The maximum number of VMs allowed per user."
            }
        },
        "maxAllowedVmsPerUserStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of VMs allowed per user policy."
            }
        },
        "maxAllowedPremiumVmsPerUser": {
            "type": "int",
            "defaultValue": 1,
            "metadata": {
                "description": "The maximum number of premium VMs allowed per user."
            }
        },
        "maxAllowedPremiumVmsPerUserStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of premium VMs allowed per user policy."
            }
        },
        "maxAllowedVmsPerLab": {
            "type": "int",
            "defaultValue": 100,
            "metadata": {
                "description": "The maximum number of VMs allowed per lab."
            }
        },
        "maxAllowedVmsPerLabStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of VMs allowed per lab policy."
            }
        },
        "maxAllowedPremiumVmsPerLab": {
            "type": "int",
            "defaultValue": 100,
            "metadata": {
                "description": "The maximum number of premium VMs allowed per lab."
            }
        },
        "maxAllowedPremiumVmsPerLabStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the maximum number of premium VMs allowed per lab policy."
            }
        },
        "allowedVmSizes": {
            "type": "string",
            "defaultValue": "\"Standard_A5\", \"Standard_A3\", \"Standard_A2\"",
            "metadata": {
                "description": "A comma-separated list of VM sizes that are allowed in the lab."
            }
        },
        "allowedVmSizesStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable VM sizes allowed per lab policy."
            }
        },
        "allowedGalleryImages": {
            "type": "string",
            "defaultValue": "\"{\\\"offer\\\":\\\"CentOS\\\",\\\"publisher\\\":\\\"OpenLogic\\\",\\\"sku\\\":\\\"7.2\\\",\\\"osType\\\":\\\"Linux\\\",\\\"version\\\":\\\"latest\\\"}\",\"{\\\"offer\\\":\\\"Oracle-Linux\\\",\\\"publisher\\\":\\\"Oracle\\\",\\\"sku\\\":\\\"7.2\\\",\\\"osType\\\":\\\"Linux\\\",\\\"version\\\":\\\"latest\\\"}\",\"{\\\"offer\\\":\\\"SQL2016-WS2012R2\\\",\\\"publisher\\\":\\\"MicrosoftSQLServer\\\",\\\"sku\\\":\\\"Enterprise\\\",\\\"osType\\\":\\\"Windows\\\",\\\"version\\\":\\\"latest\\\"}\"",
            "metadata": {
                "description": "A list of gallery images that are allowed in the lab."
            }
        },
        "allowedGalleryImagesStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the allowed gallery images policy."
            }
        },
        "allowedEnvironmentTemplates": {
            "type": "string",
            "defaultValue": "\"{\\\"armTemplateName\\\":\\\"WebApp-SQL\\\",\\\"repositorySourceName\\\":\\\"Public Environment Repo\\\"}\",\"{\\\"armTemplateName\\\":\\\"WebApp\\\",\\\"repositorySourceName\\\":\\\"Public Environment Repo\\\"}\"",
            "metadata": {
                "description": "A list of environment templates that are allowed in the lab."
            }
        },
        "allowedEnvironmentTemplatesStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the allowed environment templates policy."
            }
        },
        "publicArtifactRepoStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of public artifacts."
            }
        },
        "publicEnvironmentRepoStatus": {
            "type": "string",
            "defaultValue": "Enabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of public environment templates."
            }
        },
        "privateRepoStatus": {
            "type": "string",
            "defaultValue": "Disabled",
            "allowedValues": [
                "Enabled",
                "Disabled"
            ],
            "metadata": {
                "description": "Enabled or disable the usage of private artifacts and environment templates."
            }
        },
        "privateRepoUri": {
            "type": "string",
            "defaultValue": "https://dev.azure.com/tenant-name/project-name/_git/repo-name",
            "metadata": {
                "description": "The artifact source's URI."
            }
        },
        "privateRepoFolderEnvironments": {
            "type": "string",
            "defaultValue": "environments/",
            "metadata": {
                "description": "The folder containing environment (Azure Resource Manager) templates."
            }
        },
        "privateRepoFolderArtifacts": {
            "type": "string",
            "defaultValue": "artifacts/",
            "metadata": {
                "description": "The folder containing artifacts."
            }
        },
        "privateRepoBranchRef": {
            "type": "string",
            "defaultValue": "master",
            "metadata": {
                "description": "The artifact source's branch reference."
            }
        },
        "privateRepoDisplayName": {
            "type": "string",
            "defaultValue": "Private Repo",
            "metadata": {
                "description": "The artifact source's display name."
            }
        },
        "privateRepoType": {
            "type": "string",
            "defaultValue": "VsoGit",
            "allowedValues": [
                "VsoGit",
                "GitHub"
            ],
            "metadata": {
                "description": "The artifact source's type."
            }
        },
        "privateRepoSecurityToken": {
            "type": "securestring",
            "defaultValue": "1111111111111111111111111111111111111111111111111111",
            "metadata": {
                "description": "The security token to authenticate to the artifact source."
            }
        },
        "tagsCostCenter": {
            "type": "string",
            "defaultValue": "L7330",
            "metadata": {
                "description": "The name of the cost center to bill."
            }
        },
        "tagsEnvironment": {
            "type": "string",
            "defaultValue": "non-prod",
            "allowedValues": [
                "non-prod",
                "prod"
            ],
            "metadata": {
                "description": "Are the resources used for non production or production environments."
            }
        },
        "tagsOperationsTeam": {
            "type": "string",
            "defaultValue": "ICT",
            "metadata": {
                "description": "By which operations team are the resources maintained."
            }
        },
        "tagsPlatform": {
            "type": "string",
            "defaultValue": "DevTest Labs",
            "metadata": {
                "description": "What is the purpose of the resource. For example which application use them."
            }
        }
    },
    "resources": [
        {
            "apiVersion": "2017-05-10",
            "name": "labsTemplate",
            "type": "Microsoft.Resources/deployments",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('storageAccount'), '/', 'labs.json', parameters('storageAccountSASToken'))]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {
                    "labName": {
                        "value": "[parameters('labName')]"
                    },
                    "labStorageType": {
                        "value": "[parameters('labStorageType')]"
                    },
                    "premiumDataDiskStatus": {
                        "value": "[parameters('premiumDataDiskStatus')]"
                    },
                    "environmentPermission": {
                        "value": "[parameters('environmentPermission')]"
                    },
                    "supportStatus": {
                        "value": "[parameters('supportStatus')]"
                    },
                    "supportMarkdown": {
                        "value": "[parameters('supportMarkdown')]"
                    },
                    "announcementStatus": {
                        "value": "[parameters('announcementStatus')]"
                    },
                    "announcementTitle": {
                        "value": "[parameters('announcementTitle')]"
                    },
                    "announcementMarkdown": {
                        "value": "[parameters('announcementMarkdown')]"
                    },
                    "announcementExpiration": {
                        "value": "[parameters('announcementExpiration')]"
                    },
                    "tagsCostCenter": {
                        "value": "[parameters('tagsCostCenter')]"
                    },
                    "tagsEnvironment": {
                        "value": "[parameters('tagsEnvironment')]"
                    },
                    "tagsPlatform": {
                        "value": "[parameters('tagsPlatform')]"
                    },
                    "tagsOperationsTeam": {
                        "value": "[parameters('tagsOperationsTeam')]"
                    }
                }
            }
        },
        {
            "apiVersion": "2017-05-10",
            "name": "labsSchedulesTemplate",
            "type": "Microsoft.Resources/deployments",
            "dependsOn": [
                "[resourceId('Microsoft.Resources/deployments', 'labsTemplate')]"
            ],
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('storageAccount'), '/', 'schedules.json', parameters('storageAccountSASToken'))]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {
                    "labName": {
                        "value": "[parameters('labName')]"
                    },
                    "timeZoneId": {
                        "value": "[parameters('timeZoneId')]"
                    },
                    "labVmShutDownTime": {
                        "value": "[parameters('labVmShutDownTime')]"
                    },
                    "labVmShutDownTimeStatus": {
                        "value": "[parameters('labVmShutDownTimeStatus')]"
                    },
                    "labVmStartupTime": {
                        "value": "[parameters('labVmStartupTime')]"
                    },
                    "labVmStartupStatus": {
                        "value": "[parameters('labVmStartupStatus')]"
                    },
                    "labVmStartupWeeklyRecurrence": {
                        "value": "[parameters('labVmStartupWeeklyRecurrence')]"
                    }
                }
            }
        },
        {
            "apiVersion": "2017-05-10",
            "name": "labsPoliciesTemplate",
            "type": "Microsoft.Resources/deployments",
            "dependsOn": [
                "[resourceId('Microsoft.Resources/deployments', 'labsArtifactSourcesTemplate')]"
            ],
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('storageAccount'), '/', 'policies.json', parameters('storageAccountSASToken'))]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {
                    "labName": {
                        "value": "[parameters('labName')]"
                    },
                    "scheduleEditPermission": {
                        "value": "[parameters('scheduleEditPermission')]"
                    },
                    "maxAllowedVmsPerUser": {
                        "value": "[parameters('maxAllowedVmsPerUser')]"
                    },
                    "maxAllowedVmsPerUserStatus": {
                        "value": "[parameters('maxAllowedVmsPerUserStatus')]"
                    },
                    "maxAllowedPremiumVmsPerUser": {
                        "value": "[parameters('maxAllowedPremiumVmsPerUser')]"
                    },
                    "maxAllowedPremiumVmsPerUserStatus": {
                        "value": "[parameters('maxAllowedPremiumVmsPerUserStatus')]"
                    },
                    "maxAllowedVmsPerLab": {
                        "value": "[parameters('maxAllowedVmsPerLab')]"
                    },
                    "maxAllowedVmsPerLabStatus": {
                        "value": "[parameters('maxAllowedVmsPerLabStatus')]"
                    },
                    "maxAllowedPremiumVmsPerLab": {
                        "value": "[parameters('maxAllowedPremiumVmsPerLab')]"
                    },
                    "maxAllowedPremiumVmsPerLabStatus": {
                        "value": "[parameters('maxAllowedPremiumVmsPerLabStatus')]"
                    },
                    "allowedVmSizes": {
                        "value": "[parameters('allowedVmSizes')]"
                    },
                    "allowedVmSizesStatus": {
                        "value": "[parameters('allowedVmSizesStatus')]"
                    },
                    "allowedGalleryImages": {
                        "value": "[parameters('allowedGalleryImages')]"
                    },
                    "allowedGalleryImagesStatus": {
                        "value": "[parameters('allowedGalleryImagesStatus')]"
                    },
                    "allowedEnvironmentTemplates": {
                        "value": "[parameters('allowedEnvironmentTemplates')]"
                    },
                    "allowedEnvironmentTemplatesStatus": {
                        "value": "[parameters('allowedEnvironmentTemplatesStatus')]"
                    }
                }
            }
        },
        {
            "apiVersion": "2017-05-10",
            "name": "labsArtifactSourcesTemplate",
            "type": "Microsoft.Resources/deployments",
            "dependsOn": [
                "[resourceId('Microsoft.Resources/deployments', 'labsTemplate')]"
            ],
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('storageAccount'), '/', 'artifact-sources.json', parameters('storageAccountSASToken'))]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {
                    "labName": {
                        "value": "[parameters('labName')]"
                    },
                    "publicArtifactRepoStatus": {
                        "value": "[parameters('publicArtifactRepoStatus')]"
                    },
                    "publicEnvironmentRepoStatus": {
                        "value": "[parameters('publicEnvironmentRepoStatus')]"
                    },
                    "privateRepoStatus": {
                        "value": "[parameters('privateRepoStatus')]"
                    },
                    "privateRepoUri": {
                        "value": "[parameters('privateRepoUri')]"
                    },
                    "privateRepoFolderEnvironments": {
                        "value": "[parameters('privateRepoFolderEnvironments')]"
                    },
                    "privateRepoFolderArtifacts": {
                        "value": "[parameters('privateRepoFolderArtifacts')]"
                    },
                    "privateRepoBranchRef": {
                        "value": "[parameters('privateRepoBranchRef')]"
                    },
                    "privateRepoDisplayName": {
                        "value": "[parameters('privateRepoDisplayName')]"
                    },
                    "privateRepoType": {
                        "value": "[parameters('privateRepoType')]"
                    },
                    "privateRepoSecurityToken": {
                        "value": "[parameters('privateRepoSecurityToken')]"
                    }
                }
            }
        },
        {
            "apiVersion": "2017-05-10",
            "name": "labsVirtualNetworksTemplate",
            "type": "Microsoft.Resources/deployments",
            "dependsOn": [
                "[resourceId('Microsoft.Resources/deployments', 'labsTemplate')]"
            ],
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('storageAccount'), '/', 'virtual-networks.json', parameters('storageAccountSASToken'))]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {
                    "labName": {
                        "value": "[parameters('labName')]"
                    }
                }
            }
        }
    ]
}

Comments

Popular posts from this blog

CS8357: The specified version string contains wildcards, which are not compatible with determinism.

Today I was busy with creating a WCF service solution in Visual Studio Enterprise 2017 (15.9.2). In this solution I use a few C# class libraries based on .NET 4.7.2. When I compiled the solution I got this error message: Error CS8357: The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation The error message is linking to my AssemblyInfo.cs file of the Class library projects. In all the projects of this solution I use the wildcard notation for generating build and revision numbers. // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.

Make steps conditional in multi-stage YAML pipelines

To make the switch from the graphical release pipelines in Azure DevOps I am missing two features. The first one is to be able to defer a deploy and the second one is to exclude certain deployment steps without the need for editing the YAML file.  The defer option is something Microsoft has to solve in their Azure DevOps proposition. It's a feature which you have in the graphical release pipeline but what they have not implemented yet in their YAML pipeline replacement. Approvals and certain gate conditions are implemented on the environment but the defer option is still missing .  Pipeline The conditional deployment option can be implemented with the help of runtime parameters and expressions . In the parameter section you define boolean parameters which will control the deploy behavior. With the expressions you can control which stage/job/task should be executed when the pipeline runs. In the below YAML sample I experimented with conditions in the azure-pipelines.yml  file

Fixing HTTP Error 401.2 unauthorized on local IIS

Sometimes the Windows Authentication got broken on IIS servers so you cannot log in locally on the server. In that case you get the dreadfully error message HTTP Error 401.2 - Unauthorized You are not authorized to view this page due to invalid authentication headers. To fix this issue you can repair the Windows Authentication feature with the following PowerShell commands: Remove-WindowsFeature Web-Windows-Auth Add-WindowsFeature Web-Windows-Auth