Test your PowerShell DSC configuration on Azure VM

Troubleshooting and debugging PowerShell DSC configurations could be sometimes very painful. If you are preparing your DSC configuration to use in Azure or even on-premises, you would like to test it in the real environment.

One of the simplest method is to create empty Azure VM and push your configuration via PowerShell Desire State Configuration extension.  For example, if we want to create IIS Web Server joined to Active Directory domain we will need following configuration:

Configuration IISWebServer
        [PSCredential] $DomainJoinCredential
    Import-DscResource -ModuleName xComputerManagement
    Node $NodeName
            ActionAfterReboot = 'ContinueConfiguration'            
            ConfigurationMode = 'ApplyOnly'            
            RebootNodeIfNeeded = $true            
        WindowsFeature IIS
          Ensure = "Present"
          Name = "Web-Server"

        WindowsFeature ASP
          Ensure = "Present"
          Name = "Web-Asp-Net45"

        WindowsFeature WebServerManagementConsole
            Name = "Web-Mgmt-Console"
            Ensure = "Present"

        xComputer IISWebServerVM {
            Name = $NodeName
            DomainName = $DomainJoinName
            Credential = $DomainJoinCredential
            DependsOn = "[WindowsFeature]IIS", "[WindowsFeature]ASP", "[WindowsFeature]WebServerManagementConsole"

        Group AllowRemoteConnect {
            Ensure = "Present"
            GroupName = "Remote Desktop Users"
            MembersToInclude = $RemoteUserName
            Credential = $DomainJoinCredential
            DependsOn = "[xComputer]IISWebServerVM"


If you need more complex environment then just a one server you can develop an ARM Template to simplify redeployment.

Now you should organize your folders, I will use following structure:

.\dsc\xComputerManagement # DSC Experimental Resources need for xComputer: 
                          # https://github.com/PowerShell/xComputerManagement
.\dsc\IISWebServer.ps1    # DSC Configuration
                          # Name of the file should match the name of configuration inside this file
.\ConfigurationData.psd1  # Configuration Data File
.\Test-Configuration.ps1  # Deployment script


After it is time to zip dsc folder, upload it to Azure Blob storage and deploy Azure PowerShell DSC Extension to created Virtual Machine. Please, follow comments inside code to understand better each part:


#region Login to Azure Subscription

Select-AzureRmSubscription -SubscriptionId "{subscription_id}"


#region Artefacts Storage Parameters 

# Create Resource Group before launch of the script

$artefactsStorageResourceGroupName = "{artefacts_resource_group_name}"
$artefactsStorageName = "{artefacts_storage_name}"
$artefactsStorageLocation = "{artefacts_storage_location}"
$artefactsStorageContainerName = "{artefacts_storage_container_name}"


#region DSC Configaration Parameters

$dscConfigurationFolder = ".\dsc\"

$dscConfigurationName = "IISWebServer"
$dscConfigurationFileName = $dscConfigurationName + ".ps1"
$dscConfigurationDataFileName = "ConfigurationData.psd1"
$dscConfigurationZipFileName = $dscConfigurationFileName + ".zip"


#region Existing Azure VM and Extension Parameters 

$dscConfigurationArguments = @{ 
    NodeName = "localhost"
    DomainJoinName = "{ad_domain}"
    RemoteUserName = "{ad_domain_net}\{ad_domain_username}"
    DomainJoinCredential = Get-Credential 

# Release History : https://blogs.msdn.microsoft.com/powershell/2014/11/20/release-history-for-the-azure-dsc-extension/

$dscExtensionVersion = "2.2"

$vmResourceGroupName = "{vm_resource_group_name}"
$vmName = "{vm_name}"


#region Prepare zip-file to upload

Add-Type -AssemblyName "System.IO.Compression.FileSystem"

if (Test-Path -Path $dscConfigurationZipFileName) {
    Remove-Item -Path $dscConfigurationZipFileName

[io.compression.zipfile]::CreateFromDirectory($dscConfigurationFolder, $dscConfigurationZipFileName)


#region Upload configuration zip-file to Azure Resource Manager Blob Storage

# Create Storage Account if it does not exist

$storage = Get-AzureRmStorageAccount -ResourceGroupName $artefactsStorageResourceGroupName  `
        -Name $artefactsStorageName -ErrorAction SilentlyContinue

if (!$storage) {
    $storage = New-AzureRmStorageAccount -ResourceGroupName $artefactsStorageResourceGroupName `
                                -Name $artefactsStorageName `
                                -Location $artefactsStorageLocation `
                                -SkuName Standard_LRS

# Get Storage Account keys and context

$storageKeys = Get-AzureRmStorageAccountKey -ResourceGroupName $storage.ResourceGroupName -Name $storage.StorageAccountName
$storageContext = New-AzureStorageContext -StorageAccountName $storage.StorageAccountName -StorageAccountKey $storageKeys[0].Value

# Create Container if it does not exist

$storageContainer = Get-AzureStorageContainer -Name $artefactsStorageContainerName -Context $storageContext -ErrorAction SilentlyContinue

if (!$storageContainer) {
    $storageContainer = New-AzureStorageContainer -Name $artefactsStorageContainerName -Context $storageContext 

# Overwrite the file on blob storage

$blob = Set-AzureStorageBlobContent -File $dscConfigurationZipFileName  `
        -Container $storageContainer.Name `
        -Context $storageContext `


#region DSC Extension

# Update DSC Extension with new DSC configuration 

Set-AzureRmVMDscExtension -ResourceGroupName $vmResourceGroupName `
    -VMName $vmName `
    -ArchiveBlobName $blob.Name `
    -ArchiveStorageAccountName $storage.StorageAccountName `
    -ArchiveResourceGroupName $storage.ResourceGroupName `
    -ArchiveContainerName $storageContainer.Name `
    -ConfigurationName $dscConfigurationName `
    -ConfigurationArgument $dscConfigurationArguments `
    -ConfigurationData $dscConfigurationDataFileName `
    -Version $dscExtensionVersion `



The configuration data with PSDscAllowDomainUser and PSDscAllowPlainTextPassword can be useful during DSC debugging but in the real projects we should encrypt credentials with our own certificate.


    AllNodes = 
                NodeName           = "localhost"
                PSDscAllowDomainUser = $true
                PSDscAllowPlainTextPassword = $true


The last thing is to launch the script Test-Configuration.ps1 for each modification of DSC configuration file until Success status.

You can check the detailed status with execution log and errors on Azure Portal:

Virtual Machines -> [your vm] -> Extensions -> Microsoft.PowerShell.DSC -> View detailed status

or to examine full logs inside your Virtual Machine:


the detailed status that you see on Azure Portal is inside following folder: