Automated deployment of environments in Azure DevTest Labs


Azure DevTest Labs provide the ability to use an Azure Resource Management Manager template to create a set of resources in the lab, aka an Environment. These environments can contain any Azure resources that can be created using the ARM templates1. DevTest Lab environments allow users to readily deploy more complex infrastructures in a consistent way within the confines of the lab. Currently adding an environment to a DevTest Lab using the Azure Portal is feasible when creating it once, but in a development or a testing situation, where multiple creations occur, an automated deployment allows for an improved experience.

There are a couple of components to the workflow; the first is to create the ARM templates that define the resources being created. The second is setting up the ARM templates in a repository connected to the lab. The final step would be to pass the necessary parameters to the ARM Template and generate a script file that would be used to create the environment.

Create an ARM template

Here is an example of an ARM template that creates a simple Windows VM with all the necessary supporting infrastructure.

Setup DevTest Lab repository

If a DevTest Lab hasn’t been created yet, here is a walkthrough to get that resource in place. Once the lab is created, here is a walk through for linking a repository to the lab where the ARM template will be stored allowing the lab access.

Walk through the script

This example will create an environment based on any ARM templates in the lab.

Input Parameters

Let’s walk through the script starting with the inputs:

$SubscriptionId : The Azure Subscription ID where the DevTest Lab is created. If the Subscription Name is the preferred way of setting the Azure context, change the call to Set-AzureRmContext to use the parameter -SubscriptionName instead of ID.

$LabName : The name of the DevTest Lab in which to create the environment.

$RepositoryName : The name of the repository in the lab.

$EnvironmentName : The name of the environment within the lab that is going to be created.

$TemplateName : The display name for the template, this is used to retrieve the necessary information to create the armTemplateId.

$Params : The parameters to be passed to the environment template. Each parameter is prefixed with “-param_”. For example, if the environment template has a parameter named “TestVMName” with a value of “MyVMName”, the string in $Params would have the form “-param_TestVMName ‘MyVMName’”. This convention allows the script to dynamically handle different templates.

Getting Support Data

The next section is used to get the necessary support information:

Login to Azure and set the proper Subscription where the lab exists.

Login-AzureRmAccount
Set-AzureRmContext -SubscriptionId $SubscriptionId | Out-Null

Get the User Object ID which will be used later to set the environment, and have it assigned to the current user.

$UserId = $((Get-AzureRmADUser -UserPrincipalName (Get-AzureRmContext).Account).Id.Guid) 

Gets the lab object which contains information like the resource group name and location.

$lab = Find-AzureRmResource -ResourceType "Microsoft.DevTestLab/labs" -ResourceNameEquals $LabName

A lab can have multiple repositories, the following code snippet retrieves all the lab repository information and compares to the appropriate name.

$repository = Get-AzureRmResource -ResourceGroupName $lab.ResourceGroupName 
`-ResourceType 'Microsoft.DevTestLab/labs/artifactsources' `
-ResourceName $LabName `
-ApiVersion 2016-05-15 `
| Where-Object { $RepositoryName -in ($_.Name, $_.Properties.displayName) } `
| Select-Object -First 1

if ($repository -eq $null) { 
throw "Unable to find repository $RepositoryName in lab $LabName." 
}

The internal template information will need to be used, so the following code snippet gets the necessary information using the environment name.

$template = Get-AzureRmResource -ResourceGroupName $lab.ResourceGroupName `
-ResourceType "Microsoft.DevTestLab/labs/artifactSources/armTemplates" `
-ResourceName "$LabName/$($repository.Name)" `
-ApiVersion 2016-05-15 `
| Where-Object { $TemplateName -in ($_.Name, $_.Properties.displayName) } `
| Select-Object -First 1
if ($template -eq $null) { 
throw "Unable to find template $TemplateName in lab $LabName." 
}

Template parameters

The custom parameters will need to be extracted from $Params and formatted as name/value pairs.

$parameters = Get-Member -InputObject $template.Properties.contents.parameters -MemberType NoteProperty | Select-Object -ExpandProperty Name
$templateParameters = @()

$Params | ForEach-Object { if ($_ -match '^-param_(.*)' -and $Matches[1] -in $parameters) { $name = $Matches[1] } elseif ( $name ) { $templateParameters += @{ "name" = "$name"; "value" = "$_" } $name = $null #reset name variable } }


Once we isolate the name/value pairs, we need to create an object to hold the necessary template properties, including the template.ResourceID and the parameters to be passed into the template.

$templateProperties = @{ "deploymentProperties" = @{ "armTemplateId" = "$($template.ResourceId)"; "parameters" = $templateParameters }; }

Create Environment

The last command in the script is the call to New-AzureRmResource, which initiates the environment creation process with the specified properties. The properties include the information expected by the ARM template and which help configure the environment accordingly.

New-AzureRmResource -Location $Lab.Location `
-ResourceGroupName $lab.ResourceGroupName `
-Properties $templateProperties `
-ResourceType 'Microsoft.DevTestLab/labs/users/environments' `
-ResourceName "$LabName/$UserId/$EnvironmentName" `
-ApiVersion '2016-05-15' -Force

1 The exception is that DevTest Lab resources cannot be created within a DTL environment. DevTest Lab resources can be created either using the Azure portal, an ARM template, or the Azure CLI

Sources

The complete script and template json are below.

<#
The MIT License (MIT)
Copyright (c) Microsoft Corporation  
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

.SYNOPSIS
This script creates a new environment in the lab using an existing environment template.
.PARAMETER SubscriptionId
The subscription ID that the lab is created in.
.PARAMETER LabName
The name of the resource for the lab. Note, this is not the resource group for the lab.
.PARAMETER RepositoryName
The name of the repository in the lab.
.PARAMETER EnvironmentName
The name of the environment in the lab
.PARAMETER TemplateName
The template the environment will be based on.

.PARAMETER Params
The parameters pairs to be passed into the template ie params_TestVMAdminUserName = adminuser params_TestVMAdminPassword = pwd

.NOTES

The script assumes that a lab exists, has a repository connected, and the environment template is in the repository.

#>

#Requires -Version 3.0
#Requires -Module AzureRM.Resources

[CmdletBinding()]

param (
[string] [Parameter(Mandatory=$true)] $SubscriptionId,
[string] [Parameter(Mandatory=$true)] $LabName,
[string] [Parameter(Mandatory=$true)] $RepositoryName,
[string] [Parameter(Mandatory=$true)] $EnvironmentName,
[string] [Parameter(Mandatory=$true)] $TemplateName,
        
[Parameter(ValueFromRemainingArguments=$true)]
$Params
)
    
Login-AzureRmAccount
 
Set-AzureRmContext -SubscriptionId $SubscriptionId | Out-Null

$UserId = $((Get-AzureRmADUser -UserPrincipalName (Get-AzureRmContext).Account).Id.Guid)
        
$lab = Find-AzureRmResource -ResourceType "Microsoft.DevTestLab/labs" -ResourceNameEquals $LabName 
if ($lab -eq $null) { throw "Unable to find lab $LabName in subscription $SubscriptionId." } 
    
$repository = Get-AzureRmResource -ResourceGroupName $lab.ResourceGroupName `
    -ResourceType 'Microsoft.DevTestLab/labs/artifactsources' `
    -ResourceName $LabName `
    -ApiVersion 2016-05-15 `
    | Where-Object { $RepositoryName -in ($_.Name, $_.Properties.displayName) } `
    | Select-Object -First 1
if ($repository -eq $null) { throw "Unable to find repository $RepositoryName in lab $LabName." } 
    
$template = Get-AzureRmResource -ResourceGroupName $lab.ResourceGroupName `
    -ResourceType "Microsoft.DevTestLab/labs/artifactSources/armTemplates" `
    -ResourceName "$LabName/$($repository.Name)" `
    -ApiVersion 2016-05-15 `
    | Where-Object { $TemplateName -in ($_.Name, $_.Properties.displayName) } `
    | Select-Object -First 1
if ($template -eq $null) { throw "Unable to find template $TemplateName in lab $LabName." } 
    
$parameters = Get-Member -InputObject $template.Properties.contents.parameters -MemberType NoteProperty | Select-Object -ExpandProperty Name
$templateParameters = @()

$Params | ForEach-Object {
    if ($_ -match '^-param_(.*)' -and $Matches[1] -in $parameters) {
        $name = $Matches[1]                
    } elseif ( $name ) {
        $templateParameters += @{ "name" = "$name"; "value" = "$_" }
        $name = $null #reset name variable
    }
}
    
$templateProperties = @{ "deploymentProperties" = @{ "armTemplateId" = "$($template.ResourceId)"; "parameters" = $templateParameters }; } 
        
New-AzureRmResource -Location $Lab.Location `
    -ResourceGroupName $lab.ResourceGroupName `
    -Properties $templateProperties `
    -ResourceType 'Microsoft.DevTestLab/labs/users/environments' `
    -ResourceName "$LabName/$UserId/$EnvironmentName" `
    -ApiVersion '2016-05-15' -Force 
 
Write-Output "Environment $EnvironmentName completed."

If you have any questions about DevTest Labs, please check out the MSDN forum.

Hope this helps.

clip_image002[6] Roger Best, Senior Software Engineer

Roger is part of the Visual Studio and .NET engineering team focused on Visual Studio and Azure customers. He has been at Microsoft for 19 years, focusing on developer technologies for the past decade or so. In his spare time, he watches too many movies, and tries to survive triathlons.

clip_image004[6] Elizabeth Maher, Senior Software Engineer

Elizabeth is part of the Visual Studio and .Net engineering team focused on Visual Studio and Azure customers. She has been at Microsoft for 14 years, working on various developer technologies.


Comments (0)

Skip to main content