Introducing the Azure PowerShell DSC (Desired State Configuration) extension

PowerShell Team

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.

For the latest information regarding DSC Extension, refer to the product documentation.

……….

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.

Once you have installed and configured Azure PowerShell and authenticated to Azure, you can use the Get-AzureVMAvailableExtension cmdlet to see the PowerShell DSC extension.

PS C:\> Get-AzureVMAvailableExtension -Publisher Microsoft.PowerShell                                                   
                                                                                                                        
Publisher                  : Microsoft.Powershell                                                                       
ExtensionName              : DSC                                                                                        
Version                    : 1.0                                                                                        
PublicConfigurationSchema  :                                                                                            
PrivateConfigurationSchema :                                                                                            
SampleConfig               :                                                                                            
ReplicationCompleted       : True                                                                                       
Eula                       : http://azure.microsoft.com/en-us/support/legal/                                            
PrivacyUri                 : http://www.microsoft.com/                                                                  
HomepageUri                : http://blogs.msdn.com/b/powershell/                                                        
IsJsonExtension            : True                                                                                       

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):

001 002 003 004 005 006 007 008 009 010 011 012
configuration IISInstall {     node (“localhost”)     {         WindowsFeature IIS         {             Ensure = “Present”             Name = “Web-Server”                               }     } }

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.

PS C:\> Publish-AzureVMDscConfiguration -ConfigurationPath C:\examples\IISInstall.ps1                                   

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

https://examples.blob.core.windows.net/windows-powershell-dsc/IISInstall.ps1.zip

“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):

001 002 003 004 005 006 007 008

$vm = New-AzureVMConfig -Name “example-1” -InstanceSize Small -ImageName “a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201407.01-en.us-127GB.vhd” 

$vm = Add-AzureProvisioningConfig -VM $vm -Windows -AdminUsername “admin_account” -Password “Bull_dog1”

$vm = Set-AzureVMDSCExtension -VM $vm -ConfigurationArchive “IISInstall.ps1.zip” -ConfigurationName “IISInstall” 

New-AzureVM -VM $vm -Location “West US” -ServiceName “example-1-svc” -WaitForBoot

New-AzureVMConfig, Add-AzureProvisioningConfig, and New-AzureVM are the existing Azure cmdlets used to create a VM. The new kid on the block is Set-AzureVMDscExtension  (line 5 of above example).

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).

PS C:\> C:\examples\example-1.ps1                                                                                       
                                                                                                                        
OperationDescription          OperationId                             OperationStatus                         
--------------------          -----------                             ---------------                         
New-AzureVM                   9cfb922d-db5b-cdd0-9c74-1a4e34b91e28    Succeeded                               
New-AzureVM                   17acca22-c6ff-cb5a-8116-a41ff9764d35    Succeeded                               
                                                                                                                        

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):

iis

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.

(NOTE: I saved this script as C:\examples\FourthCoffee.ps1)

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049

configuration FourthCoffee {     Import-DscResource -Module xWebAdministration            

    # Install the IIS role     WindowsFeature IIS      {          Ensure          = “Present”          Name            = “Web-Server”      }        # Install the ASP .NET 4.5 role     WindowsFeature AspNet45      {          Ensure          = “Present”          Name            = “Web-Asp-Net45”      }        # Stop the default website     xWebsite DefaultSite      {          Ensure          = “Present”          Name            = “Default Web Site”          State           = “Stopped”          PhysicalPath    = “C:\inetpub\wwwroot”          DependsOn       = “[WindowsFeature]IIS”      }        # Copy the website content     File WebContent      {          Ensure          = “Present”          SourcePath      = “C:\Program Files\WindowsPowerShell\Modules\xWebAdministration\BakeryWebsite”         DestinationPath = “C:\inetpub\FourthCoffee”         Recurse         = $true          Type            = “Directory”          DependsOn       = “[WindowsFeature]AspNet45”      } 

    # Create a new website     xWebsite BakeryWebSite      {          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):

PS C:\> Publish-AzureVMDscConfiguration C:\examples\FourthCoffee.ps1 `                                                  
>>> -ConfigurationArchivePath C:\examples\FourthCoffee.ps1.zip

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:

FourthCoffee.ps1.zip

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)

xWebAdministration

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

fourth coffee zip

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:

PS C:\> Publish-AzureVMDscConfiguration C:\examples\FourthCoffee.ps1.zip
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.

You can change the container using the –ContainerName parameter:

PS C:\> Publish-AzureVMDscConfiguration C:\examples\FourthCoffee.ps1.zip `                                              
>>> -ContainerName mycontainer

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. Also note that this example uses Update-AzureVM instead of New-AzureVM because we are applying the extension to a VM that already exists.)

001 002 003 004 005 006

$vm = Get-AzureVM -Name “example-1” -ServiceName “example-1-svc”

$vm = Set-AzureVMDSCExtension -VM $vm -ConfigurationArchive “FourthCoffee.ps1.zip” -ConfigurationName “FourthCoffee” 

$vm | Update-AzureVM

PS C:\> C:\examples\example-2.ps1                                                                                       
                                                                                                                        
OperationDescription              OperationId                             OperationStatus                         
--------------------              -----------                             ---------------                         
Update-AzureVM                    afa38e1a-5717-cac6-a6e7-6f72d0af51d2    Succeeded

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:

cupcakes 5.99

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).

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056

configuration FourthCoffee {     [CmdletBinding()]     param(         [Parameter(Mandatory=$true, Position=0)]         [string]          $WebSiteName     )

    Import-DscResource -Module xWebAdministration            

    # Install the IIS role     WindowsFeature IIS      {          Ensure          = “Present”          Name            = “Web-Server”      }        # Install the ASP .NET 4.5 role     WindowsFeature AspNet45      {          Ensure          = “Present”          Name            = “Web-Asp-Net45”      }        # Stop the default website     xWebsite DefaultSite      {          Ensure          = “Present”          Name            = “Default Web Site”          State           = “Stopped”          PhysicalPath    = “C:\inetpub\wwwroot”          DependsOn       = “[WindowsFeature]IIS”      }         # Copy the website content     File WebContent      {          Ensure          = “Present”          SourcePath      = “C:\Program Files\WindowsPowerShell\Modules\xWebAdministration\BakeryWebsite”         DestinationPath = “C:\inetpub\FourthCoffee”         Recurse         = $true          Type            = “Directory”          DependsOn       = “[WindowsFeature]AspNet45”      } 

    # Create a new website     xWebsite BakeryWebSite      {          Ensure          = “Present”          Name            = $WebSiteName         State           = “Started”          PhysicalPath    = “C:\inetpub\FourthCoffee”          DependsOn       = “[File]WebContent”      }  }

Our third example publishes the new configuration script and updates the VM that we created previously (I saved this script as C:\examples\example-3.ps1:

001 002 003 004 005 006 007 008 009 010 011

Publish-AzureVMDscConfiguration C:\examples\FourthCoffeeWithArguments.ps1

$vm = Get-AzureVM -Name “example-1” -ServiceName “example-1-svc”

$vm = Set-AzureVMDscExtension -VM $vm `         -ConfigurationArchive “FourthCoffeeWithArguments.ps1.zip” `         -ConfigurationName “FourthCoffee” `         -ConfigurationArgument @{ WebSiteName = “FourthCoffee” }

$vm | Update-AzureVM

PS C:\> C:\examples\example-3.ps1                                                                                       
                                                                                                                        
OperationDescription              OperationId                             OperationStatus                         
--------------------              -----------                             ---------------                         
Update-AzureVM                    2b6f18e7-42f2-c216-8199-edfa06b52e33    Succeeded                               

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:

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053

configuration FourthCoffee {     Import-DscResource -Module xWebAdministration            

    # Install the IIS role     WindowsFeature IIS      {          Ensure          = “Present”          Name            = “Web-Server”      }        # Install the ASP .NET 4.5 role     WindowsFeature AspNet45      {          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         xWebsite DefaultSite          {              Ensure          = “Present”              Name            = “Default Web Site”              State           = “Stopped”              PhysicalPath    = “C:\inetpub\wwwroot”              DependsOn       = “[WindowsFeature]IIS”          }            # Copy the website content         File WebContent          {              Ensure          = “Present”              SourcePath      = “C:\Program Files\WindowsPowerShell\Modules\xWebAdministration\BakeryWebsite”             DestinationPath = “C:\inetpub\FourthCoffee”             Recurse         = $true              Type            = “Directory”              DependsOn       = “[WindowsFeature]AspNet45”          } 

        # Create a new website         xWebsite BakeryWebSite          {              Ensure          = “Present”              Name            = $WebSiteName             State           = “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:

001 002 003 004 005 006 007 008 009 010 011

Publish-AzureVMDscConfiguration C:\examples\FourthCoffeeWithData.ps1

$vm = Get-AzureVM -Name “example-1” -ServiceName “example-1-svc”

$vm = Set-AzureVMDscExtension -VM $vm `         -ConfigurationArchive “FourthCoffeeWithData.ps1.zip” `         -ConfigurationName “FourthCoffee” `         -ConfigurationDataPath C:\examples\FourthCoffeeData.psd1

$vm | Update-AzureVM

C:\ PS> C:\examples\example-4.ps1                                                                                       
                                                                                                                        
OperationDescription              OperationId                             OperationStatus                         
--------------------              -----------                             ---------------                         
Update-AzureVM                    fa6a525b-c411-c213-8f57-69dc2a09df1c    Succeeded                               
                                                                                                                        

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.

001 002 003 004 005 006
$vm = Get-AzureVMServiceName “example-1-svc” –Name example-1
$rdp = Get-AzureEndpoint -Name “RDP” -VM $vm  $hostdns = (New-Object “System.Uri” $vm.DNSName).Authority  $port = $rdp.Port  Start-Process “mstsc” -ArgumentList “/V:$hostdns`:$port /w:1024 /h:768” 
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.

  • [00000003] [07/28/2014 23:57:33.02] [INFO]  Beginning installation of plugin Microsoft.Powershell.DSC.
  • [00000003] [07/28/2014 23:59:47.25] [INFO]  Successfully installed plugin Microsoft.Powershell.DSC.
  • [00000009] [07/29/2014 00:02:51.02] [INFO]  Successfully enabled plugin Microsoft.Powershell.DSC.
  • [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.

PS C:\> PS C:\WindowsAzure\Logs\Plugins\Microsoft.Powershell.DSC\1.0.0.0> dir                                           
                                                                                                                     
    Directory: C:\WindowsAzure\Logs\Plugins\Microsoft.Powershell.DSC\1.0.0.0                                        
                                                                                                                    
 Mode                LastWriteTime     Length Name                                                                   
 ----                -------------     ------ ----                                                                   
 -a---         7/29/2014  12:28 AM       1613 CommandExecution.log                                                   
 -a---         7/28/2014  11:59 PM       1429 CommandExecution_0.log                                                 
 -a---         7/29/2014  12:01 AM       2113 CommandExecution_1.log                                                 
 -a---         7/29/2014  12:02 AM       1613 CommandExecution_2.log                                                 
 -a---         7/29/2014  12:28 AM      13744 DSCBOOT_script_20140729-002759.log                                     
 -a---         7/29/2014  12:03 AM     473528 DSCLOG_metaconf__20140729-000322.json                                  
 -a---         7/29/2014  12:28 AM     713196 DSCLOG_metaconf__20140729-002823.json                                  
 -a---         7/29/2014  12:03 AM     608050 DSCLOG__20140729-000311.json                                           
 -a---         7/29/2014  12:28 AM     713196 DSCLOG__20140729-002826.json                                           

As you can see there are a number of various logs present.

“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:

Desired State Configuration Blog Series – Part 1, Information about DSC (by Michael Green, Senior Program Manager, Microsoft)

VM Agent and Extensions – part 1 (by Kundana Palagiri, Senior Program Manager, Windows Azure)

VM Agent and Extensions – Part 2 (by Kundana Palagiri, Senior Program Manager, Windows Azure)

Automating VM Customization tasks using Custom Script Extension (by Kundana Palagiri, Senior Program Manager, Windows Azure)

0 comments

Discussion is closed.

Feedback usabilla icon