Skip to content

Custom Layer

This guide describes how to implement your own custom layer. It assumes you are familiar with the Introduction and the Practical Guide.

To get started, use this command to create a new layer folder:

Create a new layer
avdcli layer new -o layerx

This command initializes a new layer folder in the path you specify with the -o parameter. The folder will contain the following files:

  • properties.json5: Contains metadata and configuration for your layer.
  • install.ps1: A non-interactive installation script for your software, which runs before Sysprep.
  • on_sessionhost_setup.ps1 (advanced): Runs on each VM during its first boot. It may run multiple times if a VM requires a reboot during deployment. Executed with SYSTEM privileges.
  • on_user_login.admin.ps1 (advanced): Runs with SYSTEM privileges when a student logs into the VM.
  • on_user_login.user.ps1 (advanced): Runs as the user when a student logs into the VM.

You can delete any of these script files if you do not need them; only properties.json5 is mandatory. If your install.ps1 script needs other files, you can add them to this folder. They will be in the current working directory when install.ps1 is executed during the image build.

Start by opening properties.json5 and setting the following properties:

  • name: Layer names commonly follow the format com.yourorganization.layername.
  • description: A brief description of the layer’s purpose.
  • author: The person or team responsible for the layer, so others know who to contact.

This is likely the most time-consuming step. You must create a non-interactive PowerShell script to install software and apply configurations for this layer. The script must be non-interactive to ensure a reproducible image and enable automated builds.

Most scripts follow a structure similar to this:

  1. Download MSI/EXE files from a public mirror or a private Storage Account using a SAS token.
  2. Execute/install the files.
  3. Set any configurations you may need for the application.

Building this script is an iterative process. We recommend setting up a local VM for testing, or an Azure VM if a local one isn’t an option. Before each test run, snapshot the VM so you can quickly revert to a clean state between iterations.

We recommend using parameters for values like software versions or IP addresses instead of hardcoding them. This makes your layer reusable for different software versions and shareable with other organizations.

To add a parameter to install.ps1, follow the example in the script generated by avdcli layer new. Make sure to also declare the parameter in properties.json5, where you’ll also find an example. You can optionally set a default value or a list of allowed (enum) values for the parameter.

You will be prompted for these parameter values when using the layer to build an image.

By default, the Windows Firewall blocks all outgoing traffic. This means your applications won’t have direct internet access. This is by design, so consider carefully before adding exceptions. However, if you have a valid reason, use one of the following options depending on the traffic type:

  • Public HTTP(s) traffic: Use the HTTP proxy.
  • TCP/UDP to a specific IP: Add a Firewall exception.

If your application needs to make HTTP(s) connections to public domains, use the Session Host Proxy. This proxy is deployed for each exam to filter HTTP traffic. Unlike general TCP/UDP traffic, HTTP traffic is often directed to servers hosting multiple domains. This proxy allows you to whitelist specific domains while blocking others, even if they are served from the same IP address.

To use this proxy during an exam, follow these steps:

  1. Configure the allowed domains in properties.json5, under network.http_proxy_whitelist.

  2. Configure your application to use the http://proxies.local:8080 HTTP proxy. This step is unnecessary if your application already uses the Windows system proxy.

If your application requires TCP/UDP connectivity, you must add a Windows Firewall exception. Add the exceptions to your install.ps1 script using the New-NetFirewallRule command:

Allow TCP connections to 1.2.3.4:8080
New-NetFirewallRule -DisplayName 'allow-tcp' -Direction Outbound -Action Allow -RemoteAddress '1.2.3.4' -Protocol TCP -RemotePort 8080 -Profile Any -ErrorAction Stop
Allow UDP connections to 1.2.3.4:8080
New-NetFirewallRule -DisplayName 'allow-udp' -Direction Outbound -Action Allow -RemoteAddress '1.2.3.4' -Protocol UDP -RemotePort 8080 -Profile Any -ErrorAction Stop

Your layer can include the following advanced scripts that trigger on specific events:

  • on_sessionhost_setup.ps1: Runs on each VM upon first boot.
  • on_user_login.admin.ps1: Runs with SYSTEM privileges when a student logs in.
  • on_user_login.user.ps1: Runs as the logged-in user.

If you need to run code at these specific times, add your script to the corresponding file. If you don’t need them, you can safely delete these files.

Keep in mind that these scripts do not have access to other files in the layer folder when they are executed. If you need to access other files, you must copy them to a persistent location in your install.ps1 script.

Before using Azure Image Builder, test your layer in a local VM first. This is a much faster way to find errors in your scripts than waiting for the full image build process.

We recommend testing your custom layer in isolation before combining it with others in a final image. Follow the steps in the Practical Guide for this individual layer and verify that the image build completes successfully.