UPDATE 11/4/2014: For information on using PSCredential objects, please refer to this blog post.

UPDATE 11/21/2014: For information on OS support, and other features, please refer to our release history.

Earlier this year Microsoft released the Azure VM Agent and Extensions as part of the Windows Azure Infrastructure Services. VM Extensions are software components that extend the VM functionality and simplify various VM management operations; for example, the VMAccess extension can be used to reset a VM’s password, or the Custom Script extension can be used to execute a script on the VM.

Today, we are introducing the PowerShell Desired State Configuration (DSC) Extension for Azure VMs as part of the Azure PowerShell SDK. You can use new cmdlets to upload and apply a PowerShell DSC configuration on an Azure VM enabled with the PowerShell DSC extension. PowerShell DSC extension will call into PowerShell DSC to enact the received DSC configuration on the VM.

If you already have the Azure PowerShell SDK installed, you will need to update to version 0.8.6 or later.

Executing a simple scenario

One scenario in which this new extension can be used is the automation of software installation and configuration upon a machine’s initial boot-up.

As a simple example, let’s say you need to create a new VM and install IIS on it. For this, you would first create a PowerShell script that defines the configuration (NOTE: I saved this script as C:\examples\IISInstall.ps1):

Then you would use Publish-AzureVMDscConfiguration to upload your configuration to Azure storage. Publish-AzureVMDscConfiguration is one of the new cmdlets in the Azure PowerShell SDK. The example below uses all the default values, but later in this post we’ll go over more details of how this works.

This cmdlet creates a ZIP package that follows a predefined format that the PowerShell Desired State Configuration Extension can understand and then uploads it as a blob to Azure storage. The ZIP package in the above example was uploaded to

“examples” in this URI is the name of my default Azure storage account, “windows-powershell-dsc” is the default storage container used by the cmdlet, and “IISInstall.ps1.zip” is the name of the blob for the file I just published.

Now my sample configuration is available for VMs to use, so let’s write a script that creates a VM that uses our sample configuration (NOTE: I saved this script as C:\examples\example-1.ps1):

This cmdlet injects a DSC configuration into the VM configuration object ($vm in the example). When the VM machine boots, the Azure VM agent will install the PowerShell DSC Extension, which in turn will download the ZIP package that we published previously (IISInstall.ps1.zip), will execute the “IISInstall” configuration that we included as part of IISInstall.ps1, and then will invoke PowerShell DSC by calling the Start-DscConfiguration cmdlet.

Now, let’s go ahead and execute the sample script (NOTE: if you get an error telling you that the VM vhd is not available or you don’t have access to it, that likely means that the image referenced on line 1 of the script has been updated, and you will need to find the new image name. You can do so by enumerating the available images with Get-AzureVMImage and picking the image that you wish to use. See Azure SDK documentation for more details on this. In my case, I will use a 2012-R2 machine).

Our sample configuration was very simple: it just installed IIS. As a quick verification that it executed properly, we can logon to the VM and verify that IIS is installed by visiting the default web site (http://localhost):

That is the PowerShell DSC Extension in a nutshell.

And now for the gory details…

Publish-AzureVMDscConfiguration

As the previous example illustrated, the first step in using the PowerShell Desired State Configuration Extension is publishing. In this context, publishing is the process of creating a ZIP package that the extension can understand and uploading that package to Azure blob storage. This is accomplished using the Publish-AzureVMDscConfiguration cmdlet.

Why use a ZIP package for publishing? Publish-AzureVMDscConfiguration will parse your configuration looking for Import-DSCResource statements and will include a copy of the corresponding modules along with the script that contains your configuration. For example, let’s take a look at the ZIP package produced by a configuration that creates an actual website instead of just installing IIS. This new example is the FourthCoffee website, which you may have already seen in other DSC blog posts or demos). The FourthCoffee demo has a dependency on the DSC resource xWebAdministration, which is included in the DSC Resource Kit Wave 5.

# Create a new website xWebsiteBakeryWebSite{Ensure="Present"Name="FourthCoffee"State="Started"PhysicalPath="C:\inetpub\FourthCoffee"DependsOn="[File]WebContent"}}

To inspect the ZIP package created by the publish cmdlet I used the -ConfigurationArchivePath parameter, which saves the package to a local file instead of uploading it to Azure storage (NOTE: I typed the command below in two separate lines using the ` character; the >>> characters are PowerShell’s prompt):

When I look at the ZIP package using the File Explorer I can see that it contains my configuration script and a copy of the xWebAdministration module:

That copy comes from the xWebAdministration module that I already installed on my machine under “C:\Program Files\WindowsPowerShell\Modules”. The publish cmdlet requires that the imported modules are installed on your machine, and that they are located somewhere in $PSModulePath.

(NOTE: To simplify the example, I slightly altered the xWebAdministration module so it included the files needed for the website as part of the xWebAdministration module, in the “BakeryWebsite” directory)

The two previous examples use a PowerShell Script file (.ps1) to define the configuration that will be published. You can also do this in a PowerShell Module file (.psm1), or if the configuration you want to publish is part of a larger module, you can create the ZIP package manually and simply copy the directories for the module that defines your configuration and any modules referenced by your configuration. For example, if the configuration of our example was defined within a PowerShell module named FourthCoffee the ZIP package would include these two directories: the FourthCoffee module folder, and the dependent DSC resource module folder for xWebAdministration

Once you have a local ZIP package (either created manually, or using the publish cmdlet), you can upload it to Azure storage with the publish cmdlet:

ContainerName and StorageContext parameters

By default Publish-AzureVMDscConfiguration will upload the ZIP package to Azure blob storage using “windows-powershell-dsc” as the container and picking up the default storage account from the settings of your Azure subscription.

And you can change the storage account (and authentication settings) using the –StorageContext parameter (you can use the New-AzureStorageContext cmdlet to create the storage context).

Set-AzureVMDSCExtension

Once a configuration has been published, you can apply it to any Azure virtual machine using the Set-AzureVMDSCExtension cmdlet. This cmdlet injects the settings needed by the PowerShell DSC extension into a VM configuration object, which can then be applied to a new VM, as in our first example, or to an existing VM. Let’s use this cmdlet again to update the VM we created previously (NOTE: the first example used the configuration defined in C:\examples\IISInstall.ps1; now we will update this machine with the configuration defined in C:\examples\FourthCoffee.ps1; the script that we will use was saved as C:\examples\example-2.ps1)

In our first example we were working with a new VM, so the Azure VM agent first installed the PowerShell DSC Extension and then it invoked it using the information provided by the Set-AzureVMDSCExtension cmdlet. In this second example we are working on an existing VM on which the extension is already installed so the Azure VM agent will skip the installation part and just invoke the PowerShell DSC Extension with the new information provided by the set cmdlet.

The extension will then

download the ZIP package specified by the –ConfigurationArchive parameter and expand it to a temporary directory

remove the .zip extension from the value given by –ConfigurationArchive and look for a PowerShell script or module with that name and execute it (in our second example, it will look for FourthCoffee.ps1)

look for and execute the configuration named by the -ConfigurationName parameter (in this case "WebSite")

invoke the Start-DscConfiguration with the output produced by that configuration

To verify that our second configuration was applied successfully we can again check the default website:

Configuration Arguments

DSC configurations are very similar to PowerShell advanced functions and can be parameterized for greater flexibility. The PowerShell DSC extension provides support for configuration arguments via the –ConfigurationArgument parameter of Set-AzureVMDSCExtension.

As a very simple example, let’s change our last script in such a way that the name of the website is a parameter to the FourthCoffee configuration. The updated configuration has been saved as C:\examples\FourthCoffeeWithArguments.ps1; notice that we have added the $WebSiteName parameter (lines 4-7), which is used as the Name property of the BakeryWebSite resource (line 51).

The value of the –ConfigurationArgument parameter on line 8 of C:\examples\example-3.ps1 is a hashtable that specifies the arguments to the WebSite configuration, i.e. a string specifying the name of the website (this corresponds to parameter $WebSiteName, on line 7 of C:\examples\FourthCoffeeWithArguments.ps1)

Configuration Data

Configuration data can be used to separate structural configuration from environmental configuration (see this blog post for an introduction to those concepts). The PowerShell DSC extension provides support for configuration data via the –ConfigurationDataPath parameters of Set-AzureVMDSCExtension.

Let’s create another variation of the FourthCoffee configuration: IIS and ASP.NET will always be installed by the configuration, but the FourthCoffee website will be installed only if the role of the VM is “WebServer”. The updated configuration has been saved as C:\examples\FourthCoffeeWithData.ps1; the check for the VM’s role is on line 20:

# Install the IIS role WindowsFeatureIIS{Ensure="Present"Name="Web-Server"}# Install the ASP .NET 4.5 role WindowsFeatureAspNet45{Ensure="Present"Name="Web-Asp-Net45"}# Setup the website only if the role is "WebServer"Node$AllNodes.Where{$_.Role-eq"WebServer"}.NodeName{# Stop the default website xWebsiteDefaultSite{Ensure="Present"Name="Default Web Site"State="Stopped"PhysicalPath="C:\inetpub\wwwroot"DependsOn="[WindowsFeature]IIS"}# Copy the website content FileWebContent{Ensure="Present"SourcePath="C:\Program Files\WindowsPowerShell\Modules\xWebAdministration\BakeryWebsite"DestinationPath="C:\inetpub\FourthCoffee"Recurse=$trueType="Directory"DependsOn="[WindowsFeature]AspNet45"}

# Create a new website xWebsiteBakeryWebSite{Ensure="Present"Name=$WebSiteNameState="Started"PhysicalPath="C:\inetpub\FourthCoffee"DependsOn="[File]WebContent"}}}

The configuration data has been saved as C:\examples\FourthCoffeeData.psd1:

001
002
003
004
005
006
007
008
009

@{AllNodes=@(@{NodeName="localhost";Role="WebServer"});}

And the script that publishes and applies this new configuration is C:\examples\example-4.ps1:

The value of the –ConfigurationDataPath parameter on line 8 of C:\examples\example-4.ps1 is the path to a local .psd1 file containing the configuration data. A copy of this file will be uploaded to Azure blob storage and then downloaded to the VM by the PowerShell DSC Extension and passed along to the FourthCoffee configuration. This file is uploaded to the default container (“windows-powershell-dsc”) and storage account; similarly to the Publish-AzureVmDscConfiguration cmdlet, the Set-AzureVMDscExtension cmdlet includes parameters –ContainerName and –StorageContext that can be used to override those defaults.

ACQUIRING REMOTE ACCESS TO OUR VM

Since we know the name of your VM we can simply use Azure SDK cmdlets to get RDP file and kick off a remote access to it. See Azure Powershell SDK documentation for more information.

READING LOGS

Let us say that I wish to check in detail that everything went well on my VM. How would I do that? I can log in to my VM from Azure and check the local logs. The files of interest to us will be the following two locations on VM hard drive:

C:\Packages\Plugins\Microsoft.Powershell.DSC\1.0.0.0

C:\WindowsAzure\Logs\Plugins\Microsoft.Powershell.DSC\1.0.0.0

You may find that your VM has a newer version of Powershell DSC extension,in which case the version number at the end of the path might be slightly different.

“C:\Packages\Plugins\Microsoft.Powershell.DSC\1.0.0.0” contains the actual extension files. You generally don’t need to worry about this location. However, if an extension failed to install for some reason and this folder isn’t present, that is a critical issue.

Now let’s start digging into the logs: C:\WindowsAzure\Logs. This folder contains general Azure logs that were captured for us. If for some reason DSC extension failed to deploy or there was some general infrastructure error, it would appear here under log files “WaAppAgent.*.log”

The lines of interest in these files are as follows. Note that your log may look slightly different.

[00000009] [07/29/2014 00:02:51.03] [INFO] Setting the install state of the handler Microsoft.Powershell.DSC_1.0.0.0 to Enabled

Now we know that DSC extension was successfully installed and enabled. We continue our analysis by going to DSC extension logs. “C:\WindowsAzure\Logs\Plugins\Microsoft.Powershell.DSC\1.0.0.0” contains various logs from DSC extension itself.

“CommandExecution*.log” are logs written by Azure infrastructure as it enabled the DSC extension.

“DSCBOOT_script*.log” is a high level log that applied our configuration that we mentioned previously. It is fairly concise. If everything went well towards the end of the log you should be able to see a line such as this:

VERBOSE: [EXAMPLE-1] Configuration application complete.

If we wish to dig deeper into DSC logs, then the rest of logs can tell us much deeper story. “DSCLOG_*.json” logs are ETL DSC logs converted to JSON format. If configuration has completed successfully you should be able to see an event like this one:

{

"EventType": 4,

"TimeCreated": "\/Date(1406593703182)\/",

"Message": "[EXAMPLE-1]: LCM: [ End Set ] in 14.1745 seconds.",

“DSCLOG_metacong*.json” are the logs for your configuration if your PowerShell DSC configuration had a meta-config that modified PowerShell DSC properties, such as this:

LocalConfigurationManager

{

ConfigurationID = "646e48cb-3082-4a12-9fd9-f71b9a562d4e"

RefreshFrequencyMins = 23

}

You would see a similar event if meta configuration was applied successfully.

{

"EventType": 4,

"TimeCreated": "\/Date(1406593703182)\/",

"Message": "[EXAMPLE-1]: LCM: [ End Set ] in 14.1745 seconds.",

More info

Here are some additional resources about PowerShell DSC, Azure VM agent and extensions:

>>>I want to include an MSI or a script that will be executed / installed by DSC.

>>>How do I include that in the ZIP and reference it in the configuration?

Hi Brian, currently the DSC extension does not support this. One way to do it would be to include the MSI/script in a subdirectory in one of the resources that get packaged into the ZIP file that is published. This is not the best option; you may also want to consider uploading that content to azure blob storage and then reference it from your configuration using the appropriate URI.

-Norberto

organicit

8 Aug 2014 7:17 AM

For deploying the Fourth Coffee site I think the better approach would be to stage the site on Azure Files, and then have the DSC configuration map the share to the site source instead of packaging it up in the initial zip file.

Yes I agree. When I wrote the example I was trying to keep it short and I included the website content as part of the xWebAdministration resource as a shortcut. Staging the website to Azure storage would have a been a cleaner approach.

"When the VM machine boots, the Azure VM agent will install the PowerShell DSC Extension, which in turn will download the ZIP package that we published previously (IISInstall.ps1.zip), will execute the “IISInstall” configuration that we included as part of IISInstall.ps1, and then will invoke PowerShell DSC by calling the Start-DscConfiguration cmdlet."

If the configuration contains LocalConfigurationManager settings, will the DSC extension also invoke Set-DscLocalConfigurationManager in addition to Start-DscConfiguration?

"If the configuration contains LocalConfigurationManager settings, will the DSC extension also invoke Set-DscLocalConfigurationManager in addition to Start-DscConfiguration?"

Yes. The Extension takes care of applying MetaConfiguration also. We check for the existence of both meta.mof and .mof after compiling the Configuration locally on the target VM.

-Raghu

chris

25 Aug 2014 4:14 AM

I've noticed that if a Azure boot DSC configuration requires a reboot halfway through the rest of the configuration isn't applied she the machine comes back up. The Dsc boot log errors in the dscboot.ps1 script, to the effect that no configuration was found. Any idea how I can continue a applying a config after a reboot? Thanks!

Hello Chris. There is one known issue with reboot that produce "Cannot bind argument to parameter 'Path' because it is null" error message in logs. Is it the error that you get? This one should not prevent configuration setup.

Can you, please, provide a repro? Also, please, include powershell version, azure-sdk-tools version, DSC extension version. You can open an issue here: github.com/.../issues

How would one upload a configuration that uses a resource that requires a credential object such as xActiveDirectory? The credential object wouldn't be able to be decrypted once on the Azure VM correct?