Deploying the Azure DSC extension through ARM


One of the things I have been working on a lot lately is PowerShell DSC, and to give me an easily repeatable deployment process for test environments I've been making heavy use of Azure Resource Manager templates (if you're not familiar with what these are go and have a read of this - https://azure.microsoft.com/en-us/documentation/articles/powershell-azure-resource-manager/). As part of this one of the things I've been doing is automating the deployment of the DSC extension on to my freshly provisioned virtual machines. To get started with this there was some good examples on GitHub and the new tooling in the Azure SDK v2.7 make generating a starting point quite straight forward, but I wanted to document some of what I've found out about it while running with it here.

What the JSON looks like

To get started, here is a quick run down of what the JSON looks like for the DSC extension.

 {
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(variables('VMName'),'/Microsoft.Powershell.DSC')]",
"apiVersion": "2015-05-01-preview",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', variables('VMName'))]",
"[concat('Microsoft.Compute/virtualMachines/', variables('OtherVMName'),'/extensions/Microsoft.Powershell.DSC')]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.2",
"settings": {
"ModulesUrl": "[variables('DSCPackagePath')]",
"ConfigurationFunction": "MyConfiguration.ps1\\ConfigurationName",
"SasToken": "[parameters('dscSasToken')]",
"Properties": {
"ExampleProperty1": "My Value",
"exampleCredential": {
"UserName": "DEMO\\username",
"Password": "PrivateSettingsRef:DemoPassword"
}
},
"protectedSettings": {
"Items": {
"DemoPassword": "MyPassword"
}
}
}
}

In the above example you can see that the "name" value for my extension is formatted to be the name of the server I'm targeting followed by "/Microsoft.PowerShell.DSC". The computer name is how the extension knows which server this extension is going to be applied to so is kind of important to us - the second part though technically we are able to change if you like. I leave it as Microsoft.PowerShell.DSC as this is the default name that the PowerShell cmdlets go looking for when you attempt to retrieve the status of the extension (such as with Get-AzureVMDscExtensionStatus cmdlet - here I can add the "Name" property and match it what what I put in my ARM, but if I exclude it then it defaults to Microsoft.PowerShell.DSC)

Specifying which package to deploy

So the first thing you need to do is tell the extension where to get the package from which will contain the configuration you want to deploy. You can package up your configurations and dependencies using the Publish-AzureVMDscConfigurationcmdlet, and this will work regardless of how you deploy the DSC extension so start by pushing your configurations. When you push these configurations to blob storage you can use the URL for it here - if you don't change the target container it should look something like https://[accountname].blob.core.windows.net/windows-powershell-dsc/MyConfiguration.ps1.zip. This is the URL you want to put in to the "ModulesUrl" property of the above example.

The next thing you need to do is specify the name of the configuration that should be used - this goes in to the "ConfigurationFunction" property. Here you specify the name of your configuration file (so in my example above it came from MyConfiguration.ps1, and inside that file I have a Configuration element called ConfigurationName. When the DSC extension runs it will generate the MOF file file the local DSC engine on the VM to use, so this tells it which configuration needs to be generated for this VM.

Lastly since our configurations are stored in blob storage which will likely not be public, we need to generate an adhoc SAS token to access the files. From my PowerShell scripts (using ResourceManager mode) I'm able to use New-AzureStorageContainerSASToken to generate a token to give access to my "windows-powershell-dsc" container that all my configurations are uploaded to through the previous cmdlets. The SAS token needs to be passed to the "SasToken" property in the JSON above.

Creating dependencies on DSC extensions

One of the things we need to do when provisioning the extension is to tell the resource manager engine when to be able to provision our extension - for example, don't provision the extension until the VM exists, or perhaps don't do it until the DSC on another machine that I have dependencies on has finished it's DSC configuration. ARM provides us a way to create dependencies and in my above example you can see two in my "dependsOn" section:

  • the first to wait for the VM the extension will be deployed on to be finished provisioning, as it can't deploy an extension to a VM that doesn't exist yet
  • the second waits for the DSC extension on another VM to be completed, specifying the VM name and the name of the DSC extension

Passing parameters and credentials

When you manually deploy the extension through PowerShell you get the ability to pass parameters to your configurations, and using ARM is no different. The "Properties" section above demonstrates how I pass two values to my configuration, the first is a basic string called "ExampleProperty1" which is quite straight forward, it's just a name/value pair in the JSON. The second though is intended to represent a PSCredential object, where I need to ensure that the password is protected - for this we use the "protectedSettings" section. So where I define "exampleCredential" you see that there is a username there, but the password uses the "PrivateSettingsRef" prefix. This tells the extension to look for this value in the protectedSettings section. So when you look below you see the corresponding value name there and the password that I want to use here. The benefit of doing it this way is that the password will never be able to be retrieved through looking at the extension properties, and it will be encrypted on disk (which is handled by the extension). This helps us keep our passwords secure and doesn't create the risk of storing passwords in plain text and easily retrievable formats.

Selecting a version of the extension

 The last thing you will want to look at is around which version of the extension to deploy - in my above example I'm using 2.2 which is the current version at the time I wrote this post, but there are new versions coming all the time. To get a list of the available versions of all extensions that you can use you can run Get-AzureVMAvailableExtension with no parameters and see a list of everything. So looking at this list you will see the DSC extension listed  under the publisher "Microsoft.PowerShell" and it is named "DSC". You'll see the available version to list in your ARM templates.

 

So there you have it, thats a run down of how the DSC extension can be used in ARM templates. If you have any questions let me know in the comments, otherwise enjoy DSC'ing in the cloud!


Comments (4)

  1. Luke says:

    Beautifully explained. The future of deployments.

    The only negative about JSON templates and DSC is that the dsc container has to exist first. A bit of chicken-and-egg !

  2. Hi Luke,

    Yea it is a little problematic. This is why most of my automation scripts are broken up in to a few stages:

    1. Create resource group, deploy storage accounts to it

    2. Deploy DSC configurations to the storage account just created

    3. Trigger the rest of the deployment

    Its still a nice short script that uses ARM for all the heavy lifting, but yes I do accept the point about the need for the storage to exist first.

    - B

    1. Jacob says:

      What does the .JSON look like (or what ARM resource are you using) to do step #2 in your reply?

      1. It's done with the PowerShell cmdlet Publish-AzureRmVMDscConfiguration (https://docs.microsoft.com/en-us/powershell/resourcemanager/azurerm.compute/v1.3.4/publish-azurermvmdscconfiguration). You need to slip it in to the middle of the two deployment steps that would use "New-AzureRmResourceGroupDeployment" to trigger them.

Skip to main content