Azure Machine Configuration (also known as Azure Policy Guest Configuration) allows operators to configure Azure VMs OS as code via an Extension. It is like deploying an infrastructure with Bicep, Terraform, or ARM template, but for OS configuration.
It can use PowerShell DSC (v2 for Windows and v3 for Linux and Windows) or Chef InSpec for Linux.
In this post, I will cover DSC v2 for Windows.
To compile a DSC v2 configuration, you need a Windows OS machine, it won't work on Linux or macOS.
You also need several PowerShell modules, the PSDesiredStateConfiguration (but not the v3), PsdscResources, and GuestConfiguration.
install-module -name PSDesiredStateConfiguration -Repository PSGallery -MaximumVersion 2.99 -force
This allow you to install the latest v2 version of DSC.
install-module -name PsdscResources -Repository PSGallery -force
Install-Module -Name GuestConfiguration -Repository PSGallery
The DSC for the demo is simple; it just adds a registry key, ExampleKey1, with a value.
configuration demoDevTo {
Import-DscResource -ModuleName 'PSDSCResources'
Registry Registydemo
{
Ensure = "Present"
Key = "HKEY_LOCAL_MACHINE\SOFTWARE\ExampleKey1"
ValueName = "TestValue"
ValueData = "TestData"
valueType = "String"
}
}
The next step is to load the DSC configuration file on a Windows machine and compile it.
. .\demo.dsc.ps1
demoDevTo
The result is a file named localhost.mof in a demoDecTo folder.
The next step is to create a configuration package that can be consumed by Azure Machine configuration.
First the localhost.mof file needs to be renamed to demodevto.mof
rename-item -path .\demoDevTo\localhost.mof -NewName "demodevto.mof" -passThru
Then, with the help of the GuestConfiguration module, we can create the configuration package.
New-GuestConfigurationPackage -name "demodevto" -type "AuditAndSet" -Configuration ".\demoDevTo\demodevto.mof" -force $true
The cmdlet takes a name, the name of the package, a type that could be Audit (default value), to monitor the machine, or AuditAndSet for setting the state of the OS.
The cmdlet will generate a zip file containing the mof file, a metadata file, and the PowerShell module used by the DSC configuration file.
The demodevto.zip file must be sent to the container in a storage account so that VMs can download it.
$storageAccount = get-azStorageAccount -name "demodscomc001" -resourcegroup "demo-dsc"
set-azStorageBlobContent -container "packages" -file ".\demodevto.zip" -blob "demodevto.zip" -context $storageAccount.context -force
To execute the package on Azure VMs, they need a special configuration, an extension, AzurePolicyforWindows (or AzurePolicyforLinux for Linux VMs), and a system identity.
You can deploy the configuration with the same Infrastructure as Code you use to deploy the VM (Bicep ARM Template, Terraform).
For existing VMs, you can also use Azure Policy to deploy these requirements. You can use the Built-in initiative (look for “enable machine configuration policies” initiative), or you can use your policies.
Here’s an example for Windows VMs.
For the Extension
After configuring VMs, the DSC configuration can be applied to them. You can use Infrastructure as Code, or you can use Azure Policy on existing and new VMs.
For both methods, you need to have the package's SAS URI.
$today = Get-Date
$expirationDate = $today.AddYears(1)
$strPackageURI = New-AzStorageBlobSASToken -Context $storageAccount.context -Container "packages" -Blob "demodevto.zip" -Permission r -ExpiryTime $expirationDate -FullUri
If you want to deploy the configuration package using IaC, you must provide the sha-256 hash of the package zip file.
$packageHash = Get-FileHash -Path ./demodevto.zip -Algorithm SHA256
Here’s the Bicep template to deploy the configuration to an existing VM.
@description('Name of the Configuration')
param configurationName string
@description('type of assignment')
@allowed([
'ApplyAndAutoCorrect'
'ApplyAndMonitor'
'Audit'
'DeployAndAutoCorrect'
])
param assignmentType string = 'ApplyAndAutoCorrect'
@description('The SAS URI of the package')
param packageSasUri string
@description('package SHA256 hash')
param packageHash string
@description('Target VM name')
param vmName string
resource targetVM 'Microsoft.Compute/virtualMachines@2021-03-01' existing = {
name: vmName
}
resource myConfiguration 'Microsoft.GuestConfiguration/guestConfigurationAssignments@2020-06-25' = {
name: configurationName
scope: targetVM
location: resourceGroup().location
properties: {
guestConfiguration: {
name: configurationName
contentUri: packageSasUri
contentHash: packageHash
version: '1.0.0'
assignmentType: assignmentType
}
}
}
to deploy the configuration
New-AzResourceGroupDeployment -Name ParamDeployment -ResourceGroupName demo-dsc -TemplateFile ./deploy/bicep/main.bicep -configurationName "demodevto" -packageSasUri $strPackageURI -packageHash $packageHash.Hash -vmName "vm01"
To create an Azure Policy for deploying the configuration package, you need to use the New-GuestConfigurationPolicy cmdlet to help you to create the policy.
$guid = new-guid
New-GuestConfigurationPolicy -policyId $guid.Guid -ContentUri $strPackageURI -DisplayName "demoDevTo" -Description "Demo Policy for Dev.to" -path "./deploy/policy/" -platform "windows" -policyVersion "1.0.0" -Mode "ApplyAndAutoCorrect"
You need to have a Guid for the policy name, you need the blob URI of the package, a display Name and a description, the path to the folder to locally store the policy, the platform, the version of the configuration, and the mode (ApplyAndMonitor, ApplyAndAutoCorrect, or Audit).
You don't have to provide the SHA256 hash, the command will do it for you.
The command generates a deploy if not exist.
If you edit the policy, you need to ensure that the guestConfiguration metadata matches the deployment section in the policy.
"metadata": {
"category": "Guest Configuration",
"version": "1.0.0",
"requiredProviders": [
"Microsoft.GuestConfiguration"
],
"guestConfiguration": {
"name": "demodevto",
"version": "True",
"contentType": "Custom",
"contentUri": "https://demodscomc001.blob.core.windows.net/packages/demodevto.zip?sv=2023-08-03&se=2026-05-06T05%3A03%3A10Z&sr=b&sp=r&sig=6wKnMoLQ2hR4OD5cgUXBdHWOjBBDz95%2BfAT8BHOMk60%3D",
"contentHash": "8A7AEFF27A8BA4F9806E757AA9927A2A41C45F5C6ACB25024A55BA37ED17908D"
}
} "metadata": {
"category": "Guest Configuration",
"version": "1.0.0",
"requiredProviders": [
"Microsoft.GuestConfiguration"
],
"guestConfiguration": {
"name": "demodevto",
"version": "True",
"contentType": "Custom",
"contentUri": "https://demodscomc001.blob.core.windows.net/packages/demodevto.zip?sv=2023-08-03&se=2026-05-06T05%3A03%3A10Z&sr=b&sp=r&sig=6wKnMoLQ2hR4OD5cgUXBdHWOjBBDz95%2BfAT8BHOMk60%3D",
"contentHash": "8A7AEFF27A8BA4F9806E757AA9927A2A41C45F5C6ACB25024A55BA37ED17908D"
}
}
"guestConfiguration": {
"name": "demodevto",
"version": "True",
"contentType": "Custom",
"contentUri": "https://demodscomc001.blob.core.windows.net/packages/demodevto.zip?sv=2023-08-03&se=2026-05-06T05%3A03%3A10Z&sr=b&sp=r&sig=6wKnMoLQ2hR4OD5cgUXBdHWOjBBDz95%2BfAT8BHOMk60%3D",
"contentHash": "8A7AEFF27A8BA4F9806E757AA9927A2A41C45F5C6ACB25024A55BA37ED17908D",
"assignmentType": "ApplyAndAutoCorrect"
}
Also, pay attention to the "version" property in the Guest configuration; the command sets the value to "True" while it should be "1.0.0".
The "deploy if not exist" section targets Azure Virtual Machines, Azure ARC machines, and Azure Scale Set. You can remove this deployment if not needed.
The policy can be added in Azure and assigned to a VM, the deployment can be made when a new VM is created or when a remediation task is created.
At the end, you can see the result in the Azure Portal of the configuration.
Top comments (1)
Great walkthrough! Deploying DSC configs with Azure Machine Configuration really streamlines OS management as code. Thanks for the clear steps!