Desired State Configuration on Azure to automate provisioning of 2 Virtual Machines from a file upload — easy and time saving approach

Aditya Naidu
5 min readAug 4, 2023

This blog focuses on configuring the initial setup of Automation accounts for Desired State Configuration of Virtual Machines in Azure.

Steps below indicate time-saving scripts both in CLI/bash and PowerShell to ease setup constraints via web and usually is much more faster.

Github reference

Motivation behind this approach is to have a BaseLine in DevOps which states that no virtual machine shall operate without a subnet and vnet created first ; and then included the VM or VM(s) in question into those vnets and subnets.

Core concepts to be aware about in Azure are

Desired State Configuration

Azure automation runbooks

Event grid topics and endpoint configuration


Virtual Networks, Subnets, Virtual Machines , Managed Identities and Role Assignment

DSC works by executing Configuration Scripts on target nodes, which can be Azure virtual machines, virtual machines on-premises, or other cloud environments. These Configuration Scripts specify the desired state of the target nodes, such as installed software, registry settings, or file configurations.

Once the Configuration Scripts are applied to the target nodes, DSC continuously monitors and maintains the desired state by ensuring that any configuration drift is corrected automatically. This makes it easier to manage and maintain the configuration of your Azure resources, leading to increased reliability, consistency, and security.

Azure Automation runbooks are scripts or workflows that automate repetitive tasks or complex processes in the Azure environment. Runbooks can be created using PowerShell or PowerShell Workflow, and they can be executed in response to specific triggers or on a schedule.

Azure Event Grid provides a scalable and event-based messaging service that simplifies the creation and management of event-driven architectures. It allows you to define custom topics and endpoints to handle events.

Step 1 : Initial Setup and commit to Azure

Includes running the below PowerShell scripts

# Connect to azure

# Create a resource group
$rg = @{
Name = 'test-rg'
Location = 'eastus2'
New-AzResourceGroup @rg

# Create a virtual network
$vnet = @{
Name = 'vnet-1'
ResourceGroupName = 'test-rg'
Location = 'eastus2'
AddressPrefix = ''
$virtualNetwork = New-AzVirtualNetwork @vnet

# Deploy subnet within the virtual network
$subnet = @{
Name = 'subnet-1'
VirtualNetwork = $virtualNetwork
AddressPrefix = ""
$subnetConfig = Add-AzVirtualNetworkSubnetConfig @subnet

# Associate the subnet configuration
$virtualNetwork | Set-AzVirtualNetwork

$rule1 = New-AzNetworkSecurityRuleConfig -Name rdp-rule -Description "Allow RDP" `
-Access Allow -Protocol Tcp -Direction Inbound -Priority 100 -SourceAddressPrefix `
Internet -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389

# $rule2 = New-AzNetworkSecurityRuleConfig -Name web-rule -Description "Allow HTTP" `
# -Access Allow -Protocol Tcp -Direction Inbound -Priority 101 -SourceAddressPrefix `
# Internet -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 80

$nsg = New-AzNetworkSecurityGroup -ResourceGroupName 'learn-68a0cd7e-bd70-4e20-a36d-a867e72b55d0' -Location eastus2 -Name `
"nsg-1" -SecurityRules $rule1
# ,$rule2

# When acting on a storage account, reference the context instead of
# repeatedly passing in the credentials. Use the following example to
# create a storage account with locally redundant
# storage (LRS) and blob encryption (enabled by default)
$StorageHT = @{
ResourceGroupName = $rg
Name = '<storage-account-name>'
SkuName = 'Standard_LRS'
Location = $Location
$StorageAccount = New-AzStorageAccount @StorageHT
$Context = $StorageAccount.Context

# Install the prerelease version of
# the Az.ManagedServiceIdentity module to perform the user-assigned
# managed identity operations in this article.
Install-Module -Name Az.ManagedServiceIdentity -AllowPrerelease

# To create a user-assigned managed identity, your account needs the
# Managed Identity Contributor role assignment.

# To create a user-assigned managed identity, use the
# New-AzUserAssignedIdentity command. The ResourceGroupName parameter
# specifies the resource group where to create the user-assigned managed identity.
# The -Name parameter specifies its name. Replace the <RESOURCE GROUP>
# and <USER ASSIGNED IDENTITY NAME> parameter values with your own values.
New-AzUserAssignedIdentity -ResourceGroupName <RESOURCEGROUP> -Name <USER ASSIGNED IDENTITY NAME>

# To list or read a user-assigned managed identity, your
# account needs the Managed Identity Operator or Managed Identity Contributor role assignment.
Get-AzUserAssignedIdentity -ResourceGroupName <RESOURCE GROUP>

# To add an assignment of a managed identity to a subscription in Azure using PowerShell,
# you can use the New-AzRoleAssignment cmdlet. Here's an example of how to do it:
# Replace the placeholders with your own values
$managedIdentityObjectId = "<managed-identity-object-id>"
$subscriptionId = "<subscription-id>"
$roleDefinitionName = "Contributor"

# Assign the role to the managed identity
New-AzRoleAssignment `
-ObjectId $managedIdentityObjectId `
-Scope "/subscriptions/$subscriptionId" `
-RoleDefinitionName $roleDefinitionName


You may use BASH with scripts here

Step 2: Setup up Automation accounts and link them to the virtual networks of Step 1.

Note : Storage account need not be in the same virtual network .

Run the scripts here for Automation accounts using PowerShell

Note: each module needs to run replacing the place holder <ModuleName>

And module version as described in the .ps1 file comments.


# create the Automation Account using the New-AzAutomationAccount cmdlet.
# Here is an example command to create the account:
$resourceGroupName = "YourResourceGroupName"
$automationAccountName = "YourAutomationAccountName"
$location = "YourLocation"

New-AzAutomationAccount -ResourceGroupName $resourceGroupName -Name $automationAccountName -Location $location

# After creating the Automation Account, you can add variables to it using the
# Set-AzAutomationVariable cmdlet
$variableName = "YourVariableName"
$variableValue = "YourVariableValue"
$automationAccount = Get-AzAutomationAccount -ResourceGroupName $resourceGroupName -Name $automationAccountName

Set-AzAutomationVariable -AutomationAccount $automationAccount -Name $variableName -Value $variableValue

# You can also use the same cmdlet to import a module from the PowerShell Gallery directly.
# Make sure to grab ModuleName and ModuleVersion from the PowerShell Gallery.
# Az.Accouts
# Az.Automation
# Az.Compute
# Az.Network
# Az.Resource
# Az.Storage
# ImportExcel

$moduleName = <ModuleName>
$moduleVersion = <ModuleVersion>
New-AzAutomationModule -AutomationAccountName <AutomationAccountName> \
-ResourceGroupName <ResourceGroupName> -Name $moduleName \
-ContentLinkUri "$moduleName/$moduleVersion"


You may use BASH scripts here.

Note replace or add Variable values to names for each module to add to automation account.

Step 3 : Event Grid creation and adding appropriate endpoint_url from the Storage account.

Note Topic trigger is initiated on upload of file to the container of Storage account.

PowerShell script is below

# Install the Azure PowerShell module, if you haven't already,
# by running the following command in a PowerShell session:
Install-Module -Name Az -AllowClobber -Scope CurrentUser


# Create a custom Event Grid topic
New-AzEventGridTopic -ResourceGroupName <resource-group-name> \
-Location <location> -Name <topic-name>

# Retrieve the endpoint and access key for the Event Grid
# topic you just created by running the following command
$topic = Get-AzEventGridTopic \
-ResourceGroupName <resource-group-name> \
-Name <topic-name>
$endpoint = $topic.Endpoint
$key = $topic.TopicKey

# Optionally, you can create an Event Grid subscription to
# subscribe to events for the custom topic. Run the
# following command to create a subscription:
$subscription = New-AzEventGridSubscription \
-Endpoint <subscription-endpoint> \
-ResourceId <topic-resource-id>

or to use CLI/bash click here

There is documentation and walk-through on how to configure and test EventGrid endpoints which will require a video demonstration.

This will be posted in the next blog. Until then you may test initial configuration on portal and please suggest any errors you may want me to overcome.

Until next time…



Aditya Naidu

Have been working as a Techie for the past 15 years and excellence in domains such as IoT 4.0, BFSI, Telecom, e-com and more recently AI.