Creating a Virtual Machine in Azure DevTest Labs as a Lab User via Automation

Acknowledgement: This post is contributed by Elizabeth Maher and Scot Moorhead.


In tightly controlled implementations of Azure DevTest Labs, such as if often the case with enterprise-level companies, there are scenarios where users with limited permissions (e.g. DevTest Lab users) need to create resources within a lab. In most cases, doing so from the UI is more than sufficient, but in certain scenarios, this will need to be done via script. This blog post describes two approaches for automating this task.  This first approach will cover using the Azure CLI and the second approach will cover using PowerShell cmdlets.

Using the Azure CLI

If you have not already installed the CLI, you can do so by following the instructions in the Install Azure CLI 2.0 article.  To successfully use the Azure CLI commands to create a virtual machine, you will need the lab name in which the virtual machine will be created as well as the resource group and subscription id for that lab.

Before executing a DevTest Lab related commands, the appropriate Azure context must be set.  Do this by using the ‘az account set’ command.

az account set --subscription 11111111-1111-1111-1111-111111111111

The command to create a virtual machine as a DevTest Lab user is ‘az lab vm create’.  Note that the resource group for the lab, lab name and virtual machine name are all required.  The rest of the arguments change according to what type of virtual machine is being created.  Let’s go over a couple of samples to see the differences.

Below is the command to create a Windows-based image from Azure Market Place.  The name of the image is the same as you would see when creating a virtual machine using the Azure Portal.

az lab vm create --resource-group DtlResourceGroup --lab-name MyLab --name 'MyTestVm' --image "Visual Studio Community 2017 on Windows Server 2016 (x64)" --image-type gallery --size 'Standard_D2s_v3’ --admin-username 'AdminUser' --admin-password 'Password1!'

To create a virtual machine based on a custom image available in the lab, the command will be similar to the following example. Note that the image-type argument has changed from gallery to custom. Again, the name of the image will match what you will see if you were to create the virtual machine in the Azure Portal.

az lab vm create --resource-group DtlResourceGroup --lab-name MyLab --name 'MyTestVm' --image "My Custom Image" --image-type custom --size 'Standard_D2s_v3' --admin-username 'AdminUser' --admin-password 'Password1!'

You can also create virtual machines based on formulas by setting the image-type parameter to formula. If we were creating a Linux-based image, we could use the authentication-type parameter to specify ssh as the preferred remote access method. If you need to choose a specific virtual network for your virtual machine to use, the vnet-name and subnet parameters are the way to do that.

For further reading regarding managing virtual machines with Azure CLI, see DevTest Labs using the Azure CLI. This article covers creation, deletion, listing status of and how to apply artifact to virtual machines.

Using PowerShell

The ‘DevTest Lab User’ role does not have the required permissions to deploy an ARM template to the lab.  See DevTest Lab User Role Definition for all the details.  So, we will mimic what the Azure Portal does when a DevTest Lab User creates a virtual machine or environment.  Invoke-AzureRMResourceAction is useful cmdlet that allows use to invoke an action on a resource provider.  In this case, we will invoke the createEnvironment action on the lab resource.

PowerShell script to create the VM

As mentioned above, we will use the Invoke-AzureRmResourceAction cmdlet.  This cmdlet takes the resource id on which to act (i.e. the lab), the name of the action to perform (createEnvironment) and the parameters necessary perform that action.  The parameters are a hash table of all the virtual machine description properties.


[Parameter(Mandatory = $false)]  $SubscriptionId,
[Parameter(Mandatory = $true)]   $LabResourceGroup,
[Parameter(Mandatory = $true)]   $LabName,
[Parameter(Mandatory = $true)]   $NewVmName,
[Parameter(Mandatory = $true)]   $UserName,
[Parameter(Mandatory = $true)]   $Password
pushd $PSScriptRoot

try {

if ($SubscriptionId -eq $null) {
$SubscriptionId = (Get-AzureRmContext).Subscription.SubscriptionId

$API_VERSION = '2016-05-15'

$lab = Get-AzureRmResource -ResourceId "/subscriptions/$SubscriptionId/resourceGroups/$LabResourceGroup/providers/Microsoft.DevTestLab/labs/$LabName"

if ($lab -eq $null) {

throw "Unable to find lab $LabName resource group $LabResourceGroup in subscription $SubscriptionId."


#For this example, we are getting the first allowed subnet in the first virtual network

#  for the lab.

$virtualNetwork = @(Get-AzureRmResource -ResourceType  'Microsoft.DevTestLab/labs/virtualnetworks' -ResourceName $LabName -ResourceGroupName $lab.ResourceGroupName -ApiVersion $API_VERSION)[0]

$labSubnetName = $[0].labSubnetName

#Prepare all the properties needed for the createEnvironment

# call used to create the new VM.

# The properties will be slightly different depending on the base of the vm

# (a marketplace image, custom image or formula).

# The setup of the virtual network to be used may also affect the properties.

$parameters = @{

"name"      = $NewVmName;

"location"  = $lab.Location;

"properties" = @{

"labVirtualNetworkId"     = $virtualNetwork.ResourceId;

"labSubnetName"           = $labSubnetName;

"notes"                   = "Windows Server 2016 Datacenter";

"osType"                  = "windows"

"galleryImageReference"   = @{

"offer"     = "WindowsServer";

"publisher" = "MicrosoftWindowsServer";

"sku"       = "2016-Datacenter";

"osType"    = "Windows";

"version"   = "latest"


"size"                    = "Standard_DS2_v2";

"userName"                = $UserName;

"password"                = $Password;

"disallowPublicIpAddress" = $true;


#The following line is the same as invoking

#!/Labs/Labs_CreateEnvironment rest api

Invoke-AzureRmResourceAction -ResourceId $lab.ResourceId -Action 'createEnvironment' -Parameters $parameters -ApiVersion $API_VERSION -Force -Verbose


finally {



The properties for the virtual machine in the above script allow us to create a virtual machine with Windows Server 2016 DataCenter as the OS.  For each type of virtual machine, the needed properties will be slightly different.  How to determine which properties to use is covered in a later section.

Example Usage

 PS> .\Create-LabVirtualMachine.ps1 -ResourceGroupName 'MyLabResourceGroup' -LabName 'MyLab' -userName 'AdminUser' -password 'Password1!' -VMName 'MyLabVM'

Defining the Virtual Machine

Before we can create the virtual machine in the lab, we need to define it. The createEnvironment action requires a parameters hash table that describes the virtual machine being created.  There are a few ways to get this information.

Using the Azure Portal

One way to generate the base definition file is via the lab in the Azure Portal.

In this step, we’ll use the UI to generate an ARM template from which we will extract the definition for our VM. We won’t create the VM in the lab, just the template.  This is the best way to get the necessary json description if you do not already have a lab VM created.

In the Azure portal, navigate to your lab and click the “Add” button in Overview blade:

Select the base image for the virtual machines you want to create and set the configuration properties accordingly.  In this example, we will choose an Azure Market Place image.  A custom image, formula or environment can also be used as a base.   Add any artifacts needed for the virtual machine as well as set any advanced settings required.  After providing values for the required fields, and any optional fields, select “View ARM template”.

The ‘View Azure Resource Manager template’ blade will display the ARM template json needed to create a lab VM.

Scroll down to the “resources” section. Highlight and copy everything between the first and last square brackets within that section. Needed JSON will look something like the following:

 "apiVersion": "2017-04-26-preview",

  "type": "Microsoft.DevTestLab/labs/virtualmachines",

  "name": "[variables('vmName')]",

  "location": "[resourceGroup().location]",

  "properties": {
       "labVirtualNetworkId": "[variables('labVirtualNetworkId')]",

       "notes": "Windows Server 2012 R2 Datacenter",

       "<galleryImageReference": {

       "offer": "WindowsServer",

       "publisher": "MicrosoftWindowsServer",

       "sku": "2012-R2-Datacenter",

       "osType": "Windows",

       "version": "latest"


        "size": "[parameters('size')]",

        "userName": "[parameters('userName')]",
        "password": "[parameters('password')]",

        "isAuthenticationWithSshKey": false,

        "labSubnetName": "[variables('labSubnetName')]",

        "disallowPublicIpAddress": true,

        "storageType": "Premium",

        "allowClaim": false


Using Azure REST APIs

The Test Drive Azure APIs allows you to use the DevTest Lab REST APIs directly.  Don’t forgot to click the Authorize button and select ‘DevTest Labs – 2016-05-15’ resource provider before trying out any of the APIs.  Use the List Lab Virtual Machines and Get Lab Virtual Machines APIs  to get information about existing lab virtual machines.

The Create Environment API (found under the labs section of the API) is called in by Invoke-AzureRmResourceAction in the PowerShell script above.  To see a full list of available properties for the virtual machine description, click the ‘example value’ box next to the labVirtualMachineCreationParameter on the site.  Click the ‘model’ link next to labVirtualMachineCreationParameter to see a quick description of each parameter.


DevTest Labs allows users with limited access as a DevTest Lab User to create and manage their own virtual machine resources.  These abilities are not just limited to the Azure Portal.  DevTest Lab Users can automate their own tasks to save time.   We covered how to use the Azure CLI to create lab virtual machine.  We also used the Invoke-AzureRmResourceAction to call the createEnvironment action against a DevTest Labs REST API to create a lab virtual machine and learned how to determine which virtual machine parameters are needed.

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


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 15 years, working on various developer technologies.

Comments (0)

Skip to main content