ARM Templates and Bicep
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page with Pro
Lesson: Implementing Azure Virtual Desktop (AVD) Host Pools with ARM Templates and Bicep
Introduction: The Shift Toward Infrastructure as Code (IaC)
In the early days of cloud computing, administrators often relied on the Azure Portal’s graphical user interface to provision resources. While clicking through menus is intuitive for small deployments, it becomes a liability when scaling Azure Virtual Desktop (AVD) environments. Manually creating host pools, session hosts, and workspaces is prone to human error, lacks version control, and makes disaster recovery—or even simple environment replication—a significant challenge. This is where Infrastructure as Code (IaC) becomes essential.
By using ARM (Azure Resource Manager) templates or Bicep, you transform your infrastructure into documentation that is executable. Instead of describing how to build a host pool in a Word document that quickly becomes outdated, you maintain a source-controlled file that defines the exact state of your environment. This lesson explores how to use these technologies to automate the deployment of AVD host pools, ensuring your infrastructure is consistent, repeatable, and maintainable.
Understanding ARM Templates vs. Bicep
Before diving into the syntax, it is important to understand the two primary tools for deploying Azure resources. ARM templates are written in JSON (JavaScript Object Notation), which is the native language of the Azure Resource Manager API. While powerful, raw JSON is notoriously difficult to read, write, and maintain due to its verbose nature and lack of modularity.
Bicep is a domain-specific language (DSL) designed as a transparent abstraction over ARM templates. When you deploy a Bicep file, the Bicep CLI compiles it into a standard ARM template before sending it to Azure. You get all the benefits of the underlying ARM engine with a syntax that is significantly cleaner, easier to read, and modular.
Callout: Why Choose Bicep Over JSON? Bicep reduces the complexity of infrastructure files by removing the need for repetitive JSON structural elements. It supports features like modules, loops, and conditional logic that are much more readable than the equivalent logic in JSON. For any new AVD deployment project, Bicep is the industry-recommended approach.
Core Components of an AVD Host Pool Deployment
To deploy a functional AVD host pool, your code must define several interconnected resources. Understanding these dependencies is critical for writing successful templates. A typical host pool deployment requires:
- Host Pool Resource: The logical container for session host VMs.
- Application Group: The resource that manages the collection of remote apps or desktops.
- Workspace: The logical grouping that acts as the "landing page" for end-users.
- Role Assignments: Permissions that allow users to access the application groups.
Defining the Host Pool in Bicep
Let’s start by looking at how to define a basic host pool. A host pool requires a location, a name, and a pool type (Pooled or Personal).
resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2023-09-05' = {
name: 'hp-finance-prod-001'
location: 'eastus'
properties: {
hostPoolType: 'Pooled'
loadBalancerType: 'BreadthFirst'
preferredAppGroupType: 'Desktop'
maxSessionLimit: 10
}
}
In this snippet, we define a pooled host pool using the BreadthFirst algorithm, which distributes users across session hosts to ensure an even workload. By setting maxSessionLimit to 10, we control the density of our environment.
Building a Modular Deployment Strategy
One of the biggest mistakes teams make is creating a single, massive file for their entire AVD environment. As the environment grows, this file becomes impossible to manage. Instead, adopt a modular approach. Create separate files for the Host Pool, the Application Group, and the Workspace, then use a main orchestration file to link them together.
Step-by-Step: Creating a Modular Host Pool
- Create the Host Pool Module: Define the parameters for the host pool (name, location, type).
- Create the Application Group Module: Define the association with the host pool.
- Create the Workspace Module: Define the association with the application group.
- Create the Main Deployment File: Use the
modulekeyword to invoke the other three files.
This approach allows you to update the host pool configuration without risking changes to the workspace or application group settings.
Note: Managing State Unlike some third-party tools like Terraform, Azure ARM and Bicep are declarative. You define the desired state, and Azure figures out the changes required to reach that state. You do not need to worry about maintaining a "state file" manually, as Azure keeps track of your resource configuration.
Handling Session Hosts and Virtual Machines
While the host pool is the logical container, the session hosts themselves are standard Azure Virtual Machines. When deploying session hosts via templates, you must ensure they are joined to your domain (or Entra ID) and have the AVD agent installed.
Using VM Extensions for Agent Installation
The AVD agent and the Bootloader must be installed on every session host. You can automate this process using the Microsoft.Compute/virtualMachines/extensions resource type within your Bicep template.
resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2023-09-01' = {
parent: virtualMachine
name: 'AVDAgent'
location: 'eastus'
properties: {
publisher: 'Microsoft.Powershell'
type: 'DSC'
typeHandlerVersion: '2.73'
autoUpgradeMinorVersion: true
settings: {
modulesUrl: 'https://wvdportalstorageblob.blob.core.windows.net/galleryartifacts/Configuration_1.0.0.zip'
configurationFunction: 'Configuration.ps1\\AddSessionHost'
properties: {
HostPoolName: 'hp-finance-prod-001'
RegistrationInfoToken: 'YOUR_TOKEN_HERE'
}
}
}
}
Warning: Token Expiration The
RegistrationInfoTokenused in the extension is short-lived. Never hardcode this token in your source-controlled Bicep file. Instead, use Key Vault to retrieve the token at runtime or generate a fresh token as part of your deployment pipeline.
Best Practices for AVD Infrastructure
To maintain a professional-grade AVD environment, follow these industry-standard practices:
- Parameterize Everything: Do not hardcode resource names, locations, or SKU sizes. Use a
parameters.jsonfile or pass parameters through your CI/CD pipeline to keep your templates environment-agnostic. - Use Resource Tags: Apply tags for Cost Center, Environment (Dev/Test/Prod), and Owner. This is critical for billing and resource auditing.
- Implement Role-Based Access Control (RBAC): Use your templates to assign specific roles to service principals. Do not use Global Administrator accounts for deployments.
- Version Control: Store your Bicep files in a Git repository. Every change to your infrastructure should be documented via a Pull Request.
Comparison Table: ARM vs. Bicep
| Feature | ARM Templates (JSON) | Bicep |
|---|---|---|
| Readability | Low (Verbose) | High (Clean) |
| Modularity | Difficult (Linked Templates) | Built-in (Modules) |
| Validation | Post-deployment only | Compile-time validation |
| Logic/Loops | Complex/Difficult | Simple/Intuitive |
| Tooling Support | Basic | Advanced (IntelliSense/Linting) |
Avoiding Common Pitfalls
Pitfall 1: Ignoring Dependencies
Many administrators struggle with deployments failing because the Host Pool doesn't exist yet when the Application Group attempts to reference it. Use the dependsOn property or, better yet, rely on implicit dependencies by referencing the host pool resource directly in the application group configuration. Bicep is smart enough to detect these references and order the deployment accordingly.
Pitfall 2: Over-complicating Logic
Keep your Bicep files simple. If you find yourself writing complex conditional logic to handle hundreds of variations, you are likely better off splitting your deployments into smaller, more focused templates. If a template is hard to read, it is hard to debug.
Pitfall 3: Failing to Clean Up
When testing, it is easy to accumulate orphaned resources. Use Resource Groups to logically group your AVD infrastructure. When a test environment is no longer needed, deleting the Resource Group is the cleanest way to ensure no "zombie" resources remain to accrue costs.
Detailed Example: A Complete Deployment Workflow
To put this all together, let’s look at how a deployment pipeline would handle the creation of a workspace and an application group.
The Workspace Module (workspace.bicep)
param workspaceName string
param location string
resource workspace 'Microsoft.DesktopVirtualization/workspaces@2023-09-05' = {
name: workspaceName
location: location
properties: {
description: 'Workspace for Finance Department'
}
}
output workspaceId string = workspace.id
The Main Orchestrator (main.bicep)
module myWorkspace 'workspace.bicep' = {
name: 'workspaceDeployment'
params: {
workspaceName: 'FinanceWorkspace'
location: 'eastus'
}
}
module myAppGroup 'appGroup.bicep' = {
name: 'appGroupDeployment'
params: {
hostPoolId: myHostPool.id
workspaceId: myWorkspace.outputs.workspaceId
// ... other params
}
}
By passing the output of the workspace module directly into the application group module, you ensure that the resources are linked correctly without manual intervention. This pattern of "Input -> Module -> Output" is the backbone of robust infrastructure automation.
Advanced Tip: Using Bicep Registry
As your organization grows, you might find that you are repeating the same logic for host pool configurations across different projects. Instead of copying and pasting Bicep files, you can publish your modules to a private Bicep Registry (hosted in an Azure Container Registry).
This allows your team to "import" verified, standardized modules into their own projects. For example, your team could use a finance-hostpool module that already has the required tagging, security settings, and logging enabled by default, ensuring compliance across the entire organization.
Troubleshooting Deployment Failures
When a deployment fails, Azure provides an error code and a detailed message. However, these can sometimes be cryptic. Here is a checklist for debugging:
- Check the Deployment History: In the Azure Portal, navigate to the Resource Group and look at "Deployments." Click on the failed deployment to see the exact resource that caused the issue.
- Validate Locally: Use the Bicep CLI (
bicep build file.bicep) to ensure there are no syntax errors before attempting a deployment. - Check API Versions: Azure resources evolve. Ensure your
apiVersionmatches the requirements for the specific resource type you are deploying. - Confirm Permissions: Ensure the identity performing the deployment has the "Contributor" or "Desktop Virtualization Contributor" role on the target subscription or resource group.
Key Takeaways for Success
Implementing AVD infrastructure using ARM templates and Bicep is a fundamental skill for modern cloud administration. By shifting from manual clicks to code-based deployments, you gain control over your environment that is impossible to achieve otherwise.
- Consistency: Infrastructure as Code ensures that your production environment is an exact match for your staging and development environments.
- Version Control: By keeping your Bicep files in Git, you maintain a history of every change, who made it, and why, which is essential for compliance and auditing.
- Modularity: Always break your deployments into smaller, reusable modules. This makes your code easier to read, test, and maintain over time.
- Security: Avoid hardcoding secrets. Use Azure Key Vault to manage tokens and credentials required during the deployment process.
- Automation: Use CI/CD pipelines to trigger your deployments. This removes the "human element" from production changes, reducing the risk of accidental outages.
- Documentation: Your Bicep code is your documentation. Keep it clean, add comments where necessary, and ensure your team understands the structure of the modules.
- Cost Management: Use templates to enforce tagging policies. When resources are properly tagged, it is significantly easier to identify and stop unnecessary spending in your AVD environment.
By adopting these practices, you move away from being a reactive administrator and toward being a proactive cloud architect. You spend less time fixing "broken" environments and more time optimizing your AVD deployment for performance and user experience.
Common Questions (FAQ)
Q: Can I convert my existing ARM templates to Bicep?
A: Yes. The Bicep CLI includes a decompile command that can take an existing JSON ARM template and turn it into a Bicep file. Note that it may not always create the most "idiomatic" Bicep, so you might need to clean it up after the conversion.
Q: Is it safe to run Bicep deployments on live production systems? A: Yes, provided you have a proper staging environment. Always test your Bicep changes in a non-production resource group first to ensure the desired state is reached without unexpected side effects.
Q: How do I handle large-scale deployments with hundreds of VMs?
A: For large-scale AVD deployments, consider using deployment stacks or deployment scripts. These features allow you to manage the lifecycle of resources more effectively and handle complex dependencies across multiple subscriptions.
Q: Do I need to be a developer to use Bicep? A: Not at all. Bicep is designed for IT professionals. If you understand basic scripting and the structure of Azure resources, you can learn Bicep effectively. The focus is on infrastructure logic, not software development patterns.
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons