Microsoft AZ-104 - Microsoft Azure Administrator - Deploy and manage Azure Compute Resources - Automate Deployments
Automate Azure Deployments
Overview of interaction and configuration options for Azure cloud resources
Interpret an Azure Resource Manager template or a Bicep file
Modify an existing Azure Resource Manager template
Modify an existing Bicep file
Deploy resources by using an Azure Resource Manager template or a Bicep file
Export a deployment as an Azure Resource Manager template, or convert an ARM template to a Bicep file
Working with GitHub
Overview of interaction and configuration options for Azure cloud resources
Azure provides several interfaces for managing resources, but they use the same Azure Resource Manager management layer. The main choice is how you express the change: interactively, through commands, or as reusable infrastructure as code.
1. How Azure management tools connect to resources

Azure Resource Manager receives management requests and coordinates them with the appropriate resource provider. This gives the portal, scripts, and applications a consistent management foundation.
Option | Main purpose | Typical use |
Azure portal | Graphical management | Explore resources, configure settings, troubleshoot |
Azure PowerShell | Script management using the Az module | Automate administrative tasks with PowerShell cmdlets |
Azure CLI | Script management using az commands | Automate tasks from Bash, PowerShell, or pipelines |
Azure SDKs | Manage Azure from application code | Build management tools using supported programming languages |
REST API | Send HTTP requests directly | Integrate Azure management with custom systems |
Security controls serve different purposes:
Microsoft Entra ID: establishes the caller’s identity.
Azure RBAC: determines which management actions the caller can perform at a particular scope.
Azure Policy: evaluates resource configuration against organizational rules.
Resource locks: protect against certain changes or deletion.
Exam point: Creating a storage account is a management operation. Reading a blob is a data operation and requires the appropriate data access permissions.
2. Imperative commands versus declarative infrastructure as code

Approach | What you specify | Key consideration |
Interactive portal configuration | Settings entered through forms | Convenient for individual changes; repeated manual work can introduce inconsistency |
Imperative scripting | Commands and execution logic | Scripts must handle sequencing, errors, and safe reruns |
Declarative IaC | The intended resource configuration | Reusable files support consistent deployments, review, and version control |
ARM templates use JSON. Bicep provides a more concise declarative language and compiles to an ARM template for deployment. Parameters let the same definition deploy different environments, for example, development and production.
Use what-if to preview expected resource changes before deploying. Declarative files do not continuously correct configuration drift; you must compare, redeploy, or use additional governance mechanisms.
Exam points:
PowerShell and CLI can run individual commands or deploy declarative templates.
VS Code is an authoring environment, not a separate Azure deployment engine.
ARM/Bicep primarily configures Azure resources. Configuration inside a VM’s operating system may require extensions, scripts, or configuration tools.
3. Where to run tools, and how to discover existing resources

Azure Cloud Shell is a Microsoft-managed command-line environment available through a browser. It provides Azure management tools without requiring a local installation.
Choose Bash or PowerShell.
Use an ephemeral session without a storage account, or configure persistent storage.
An ephemeral session does not preserve local session files after it ends.
Verify the active subscription before running deployment commands. The older slide suggesting storage is always required no longer applies. Microsoft Learn
Azure Resource Graph provides fast queries over Azure resource metadata across the subscriptions you can access. It is useful for inventory, governance checks, and locating resources, not for querying application records or replacing Azure Monitor Logs. Results respect Azure RBAC read permissions.
For example, this Resource Graph query counts storage accounts by region:
Resources
| where type =~ 'microsoft.storage/storageaccounts'
| summarize StorageAccounts = count() by location
| order by StorageAccounts descExam memory aid: Portal for interactive management; CLI/PowerShell for commands and automation; ARM/Bicep for repeatable infrastructure definitions; Cloud Shell for a hosted terminal; Resource Graph for resource inventory queries.
Interpret an Azure Resource Manager template or a Bicep file
Both formats describe the desired configuration of Azure resources. ARM templates use JSON; Bicep provides a more concise language that compiles to ARM JSON. These files describe resource deployments, not all application data or internal Azure configuration.

Read a template by asking: What is the deployment scope? What inputs are required? Which resources will change? What dependencies and outputs exist?
Concept | ARM JSON | Bicep | Meaning |
Deployment scope | Template $schema and deployment command | targetScope and deployment command | Where the deployment runs |
Inputs | parameters | param | Values supplied at deployment |
Calculated values | variables | var | Reusable expressions |
Resource definition | Entries under resources | resource declaration | Resource type, name, API version, and configuration |
Dependencies | Usually dependsOn | Usually inferred from resource references | Required deployment order |
Reusable components | Nested or linked templates | module | Break a solution into manageable parts |
Results | outputs | output | Return resource IDs, endpoints, and other values |
ARM’s contentVersion identifies the template version; a resource’s apiVersion identifies the resource provider API contract. They serve different purposes.
For example, this Bicep declaration creates or updates a storage account:
targetScope = 'resourceGroup'
param storageName string
param location string = resourceGroup().location
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageName
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: {
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
}
}
output storageId string = storage.idHere, storage is the symbolic name used inside the Bicep file. The parameter storageName supplies the actual Azure resource name.
Exam point: File order does not establish deployment order. ARM uses dependencies and can deploy independent resources in parallel.
Modify an existing Azure Resource Manager template
Modify the template’s inputs, expressions, or resource definitions, then validate the proposed result. Use the Azure Resource Manager Tools extension for VS Code to help identify syntax and authoring problems.

Common modifications include:
Parameterizing hard-coded names, locations, or SKUs.
Changing resource properties, such as tags or minimum TLS version.
Adding resources and their dependencies.
Using conditions or loops for optional or repeated resources.
Splitting a large deployment into nested or linked templates.
For example, replace a hard-coded storage SKU with a parameter:
"parameters": {
"storageSku": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS"
]
}
}Reference it in the storage resource:
"sku": {
"name": "[parameters('storageSku')]"
}A production parameter file can supply a different value:
"parameters": {
"storageSku": {
"value": "Standard_GRS"
}
}These are excerpts from their respective files. Parameters separate reusable deployment logic from environment-specific values. Microsoft Learn
Exam points:
Changing a resource’s name generally targets a different resource, rather than renaming the existing one.
Incremental deployment is not a property-by-property patch. Specify the intended configuration of resources you redeploy; omitted properties can reset to defaults.
Keep secrets out of source control. Use secure parameters and supported Key Vault integration.
Modify an existing Bicep file
Bicep uses the same ARM deployment platform while simplifying authoring. Use the Bicep extension for VS Code for completion, diagnostics, and navigation.

For the storage example in section 1, add a constrained SKU parameter:
@allowed([
'Standard_LRS'
'Standard_GRS'
])
param storageSku string = 'Standard_LRS'Then update the resource:
sku: {
name: storageSku
}A Bicep parameter file can provide production values:
using './main.bicep'
param storageName = 'sttrainingprod001'
param storageSku = 'Standard_GRS'The storage account name must still be globally unique.
Key editing concepts:
Feature | Purpose |
param | Accept deployment inputs |
var | Calculate reusable values |
module | Reuse another Bicep file |
if | Conditionally deploy a resource or module |
for | Generate multiple resource or module instances |
existing | Reference an existing resource without deploying it |
Resource references | Access properties and establish implicit dependencies |
For example, referencing storage.id from another deployed resource typically establishes an implicit dependency. Avoid unnecessary explicit dependsOn declarations. An existing declaration references a resource; it does not create it.
Exam point: Edit the Bicep source when Bicep is your maintained definition. Editing only its generated JSON leaves the source out of sync.
4. Deploy resources using an ARM template or Bicep file
A deployment combines a template, parameter values, a target scope, and an authorized identity.

Deployment scope and permissions matter. The hierarchy is management group → subscription → resource group → resource, but ARM deployments run at tenant, management group, subscription, or resource group scope. The scope determines which resource types and operations are supported.
Deployment scope | Azure CLI command family |
Resource group | az deployment group |
Subscription | az deployment sub |
Management group | az deployment mg |
Tenant | az deployment tenant |
For an existing resource group, use Azure CLI to validate, preview, and deploy a Bicep file:
az deployment group validate \
--resource-group rg-training-dev \
--template-file main.bicep \
--parameters storageName=sttrainingdev001az deployment group what-if \
--resource-group rg-training-dev \
--template-file main.bicep \
--parameters storageName=sttrainingdev001az deployment group create \
--resource-group rg-training-dev \
--template-file main.bicep \
--parameters storageName=sttrainingdev001For ARM JSON, use the same command family with --template-file main.json. These commands are also available through Azure PowerShell equivalents. Validation and what-if reduce deployment risk, but do not guarantee success if conditions change or runtime issues arise.
Understand deployment modes:
Mode | Treatment of existing resources absent from the template |
Incremental — default | Leaves them in place |
Complete — legacy approach | Can delete them within the target resource group, subject to documented rules |
Microsoft recommends deployment stacks for managed resource deletion and is gradually deprecating complete mode. Removing a resource from an ordinary incremental template does not delete it.
Template specs store versioned deployment templates in Azure for controlled sharing and reuse.
Blueprints is undergoing phased retirement, with final retirement scheduled for January 31, 2027. Current designs should use ARM/Bicep with appropriate combinations of deployment stacks, template specs, Azure Policy, and RBAC. Microsoft Learn
5. Export a deployment as ARM JSON, or convert ARM JSON to Bicep
Exporting helps capture a starting point; decompiling helps migrate existing JSON definitions to Bicep. Neither replaces review and testing.

Choose the export source carefully:
Export source | What it represents | Key consideration |
Resource or resource group | Generated snapshot of supported current resource configuration | May contain hard-coded values or incomplete definitions |
Deployment history | Template submitted for a particular deployment | Does not include later configuration changes |
The portal supports resource exports in ARM JSON or Bicep where available. Exporting from deployment history retrieves ARM JSON.
Export a resource group to ARM JSON:
az group export \
--name rg-training-dev \
> exported.jsonDecompile ARM JSON to Bicep:
az bicep decompile --file exported.jsonCompile Bicep to ARM JSON:
az bicep build --file main.bicepBuild means Bicep → ARM JSON. Decompile means ARM JSON → Bicep. Decompilation is a best-effort conversion that may require manual fixes and restructuring. Microsoft Learn
Before reusing an export:
Replace hard-coded names and resource IDs with parameters or references.
Review API versions, dependencies, and unsupported properties.
Reorganize repeated definitions into modules.
Supply secrets securely; do not expect exports to recover passwords.
Validate and test the result.
Exam point: Exporting a template captures infrastructure configuration. It does not back up database records, blob contents, VM disk contents, or application files.
Working with GitHub
Git tracks deployment definitions and their history. Pipelines or GitOps controllers use those definitions to deploy changes to Azure. Together, they make infrastructure changes repeatable, reviewable, and traceable.
1. Git: track and review infrastructure changes

Git is a distributed version control system. It records changes to files, including infrastructure templates, scripts, parameter files, and pipeline definitions.
Concept | Purpose |
Working directory | Files you are currently editing |
Staging area | Changes selected for the next commit |
Commit | A recorded snapshot with an identifier and message |
Branch | An independent line of development |
HEAD | Usually points to the currently checked-out branch |
Remote repository | Shared repository hosted on GitHub, Azure Repos, or another service |
Pull request | A hosting-platform feature for reviewing and merging changes |
For example, an administrator creates a branch to change a storage account’s configuration, commits the change, and opens a pull request. Reviewers inspect the proposed changes before merging them.
Key points:
git init creates a local repository; git clone copies an existing repository.
Commit records changes locally. Push sends commits to a remote.
Git is the version control tool; GitHub is a collaboration and repository-hosting platform.
Store reusable definitions and nonsecret parameters in Git. Keep credentials and private keys out of the repository.
Reverting a commit changes the files. Azure resources change only after the revised definitions are deployed.
2. Pipelines: deploy reviewed templates to Azure

GitHub Actions and Azure Pipelines are two common choices for automating ARM and Bicep deployments. Both execute workflows on runners or agents, authenticate to Azure, and invoke deployment tools.
Stage | Main purpose |
CI — continuous integration | Check proposed changes: compile Bicep, validate templates, and run relevant checks |
Preview | Use what-if to examine expected resource changes |
CD — continuous delivery/deployment | Deploy an approved version with the correct environment parameters |
Verification | Inspect deployment results and confirm the resources work |
A single template can support development and production through separate parameter values. Record the commit identifier with deployment results to connect an Azure change to its source.
For GitHub Actions, workflows are stored under .github/workflows/. Azure authentication can use OpenID Connect federation, avoiding a stored, long-lived client secret. The deployment identity still needs appropriate Azure RBAC permissions.
DevTest Labs adds development environment controls. Administrators can configure scheduled VM shutdown, allowed VM sizes, and VM-count limits. These controls reduce waste after environments are provisioned; they are separate from Git version control and pipeline execution. Shutdown does not remove ongoing charges for retained resources such as disks.
Exam point: A successful pipeline means its configured steps succeeded. Include deployment verification rather than relying only on the final pipeline status.
3. AKS GitOps: continuously reconcile configuration with Git

GitOps uses a versioned repository as the source of desired configuration and a controller to reconcile the environment with it. Azure supports Flux v2 for AKS and Azure Arc-enabled Kubernetes. Flux can work with Kubernetes YAML, Helm, and Kustomize.
The attached Helm diagrams show how application deployment definitions can be packaged for reuse:
Helm component | Purpose |
Chart.yaml | Chart metadata, including name and chart version |
values.yaml | Default configuration values |
templates/ | Templates that render Kubernetes manifests |
charts/ | Chart dependencies, when present |
Packaged chart — .tgz | Distributable chart archive |
For example, a reviewed Git change updates an application’s container image reference. Flux detects the configuration change and applies it through the Kubernetes API. Kubernetes then manages the workload rollout.
Keep the responsibilities clear:
ARM/Bicep: provisions Azure resources, such as the AKS cluster and container registry.
Build pipeline: builds and publishes container images.
Helm/Kubernetes manifests: define workloads running inside the cluster.
Flux: pulls desired configuration and continuously reconciles the resources it manages.
Flux agents initiate outbound connections to their configured sources; Git does not directly push changes into the Kubernetes API server.
Exam point: A conventional deployment pipeline applies changes when it runs. GitOps adds an ongoing reconciliation loop that can correct drift in managed Kubernetes resources.

Comments