Originally posted on MSDN.
Overview
In version 2.7 of the Azure DSC Extension, we added support to leave your Virtual Machine on the latest supported version of WMF 4.0. This blog will show you how to use this feature in Azure Cloud Service Manager (ASM). This assumes you already know how to create a VM in the Azure PowerShell SDK. If you don’t please see MSDN. We are working to add this feature into the Azure Powershell SDK DSC extension Cmdlets directly. Currently the WMF 4 feature is only available if you form the JSON yourself and send it to the extension using the generic extension Cmdlet.
In this Example I will show you:
- How to Create the JSON you need to send to the extension.
- How to create URI to published configuration which will only let people with this URI access it, known as the `ModulesUrl’ to the extension.
- How to send this JSON to the extension on an existing VM.
Creating the JSON
To do this, use the Set-AzureVMExtension
Cmdlet rather than the Set-AzureVMDscExtension
Cmdlet and pass the JSON using the -PublicConfiguration
parameter. The following function New-XAzureVmDscExtensionJson
will create the JSON needed for this example.
# Create a Json to send the the DSC VM Extension
function New-XAzureVmDscExtensionJson
{
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
$moduleName,
[Parameter(Mandatory = $false)]
[ValidateNotNull()]
[string]
$modulesUrl,
[AllowNull()]
[HashTable]
$properties,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
$configurationName,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[ValidateSet('4.0','latest','5.0PP')]
[string]
$WmfVersion
)
$publicSettingsTable = @{
= $properties
Properties = $WmfVersion
WmfVersion }
if($null -ne $modulesUrl)
{
$publicSettingsTable.Add('ModulesUrl',$modulesUrl)
}
$publicSettingsTable.Add('ConfigurationFunction' , "${ModuleName}\${configurationName}")
return ConvertTo-Json -Depth 8 $publicSettingsTable
}
Here is an explanation of the values:
modulesUrl
- Should be a URL to a zip file generated by
Publish-AzureVmDscConfiguration
- Should be a URL to a zip file generated by
moduleName
- The extension will look for this file name inside the zip file for the configuration.
configurationName
- The extension will look for a Configuration with this function inside the file/module.
WmfVersion
- The version of WMF to upgrade or leave the machine on. Currently supported values:
4.0
indicating to upgrade to the currently supported version of WMF 4.0 if a newer version isn’t already installed.5.0PP
indicating to upgrade to the WMF 5.0PP.latest
indicating to upgrade to the latest version of WMF.
- The version of WMF to upgrade or leave the machine on. Currently supported values:
properties
- A Hash-table of parameters to be passed to the configuration
This function should produce a JSON that looks something like this.
"Properties": {
"DestinationPath": "C:\\test"
,
}"WmfVersion": "4.0",
"ConfigurationFunction": "configuration.ps1\\ConfigurationName",
"ModulesUrl": "https://storageaccountname.blob.core.windows.net/windows-powershell-dsc/configuration.ps1.zip?<sastoken>"
}
Creating the ModulesUrl' To generate the JSON, we need the
modulesUrlthis is the URL of the published configuration, with any querystring needed to access the URL. The following function
Get-XAzureDscPublishedModulesUrl` will publish the configuration, create a read-only SASToken for 1 hour, and return the full URI to the blob with the SASToken.
# Publish a DSC configuration, Create a SasToken, and return the full URI with the SASToken
function Get-XAzureDscPublishedModulesUrl
{
[CmdletBinding()]
param
(
[Parameter(HelpMessage='The storage container to publish the configuration to')]
[ValidateNotNullOrEmpty()]
[String]
$StorageContainer = 'windows-powershell-dsc',
[Parameter(Mandatory=$true, Position=0, HelpMessage='The name of the blob.')]
[ValidateNotNullOrEmpty()]
[String]
$blobName,
[Parameter(Mandatory=$true, Position=1, HelpMessage='The path to the configuration to publish')]
[ValidateNotNullOrEmpty()]
[String]
$configurationPath,
[Parameter(Mandatory=$true, Position=2, HelpMessage='The name of the storage account to publish to')]
[ValidateNotNullOrEmpty()]
[String]
$storageAccountName
)
# Get the Storage Account Context
function Get-AzureDscStorageAccountContext
{
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]
$storageAccountName
)
$azureStorageAccount = Get-AzureStorageAccount -StorageAccountName $storageAccountName
if(!$azureStorageAccount)
{
throw 'storage account not found'
}
$storageAccessKey = (Get-AzureStorageKey –StorageAccountName $StorageAccountName).Primary
$storageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName `
-StorageAccountKey $storageAccessKey
return $storageContext
}
$expiryTime = [DateTime]::UtcNow.AddMinutes(60)
#Publish the configuration
-ConfigurationPath $configurationPath -Verbose -Force `
Publish-AzureVMDscConfiguration -storageContext (Get-AzureDscStorageAccountContext -storageAccountName $storageAccountName) `
-ContainerName $StorageContainer
# Create a SasToken for the Configuration
return New-AzureStorageBlobSASToken -Container $StorageContainer -Blob $blobName -Permission r `
-ExpiryTime $expiryTime -Context (Get-AzureDscStorageAccountContext -storageAccountName $storageAccountName) -FullUri
}
Putting it all together and Sending it to a VM
Now we need to call the function to get the modulesUrl
, pass the value to the function to get the JSON along with the rest of the parameters, get our VM object, and call Set-AzureVMExtension
on the VM with the JSON and the parameter to send it the the DSC extension. The following is an example of how to do that.
$storageAccountName = 'storageaccountname'
$publisher = 'Microsoft.Powershell'
$dscVersion = '2.7'
$serviceName = 'servicename'
$vmName = 'vmName'
$moduleName = 'configuration.ps1'
$blobName = "$moduleName.zip"
$configurationPath = "$PSScriptRoot\$moduleName"
$ConfigurationName = 'ConfigurationName'
$modulesUrl = Get-XAzureDscPublishedModulesUrl -blobName $blobName -configurationPath $configurationPath `
-storageAccountName $storageAccountName
Write-Verbose -Message "ModulesUrl: $modulesUrl" -Verbose
$PublicConfigurationJson = New-XAzureVmDscExtensionJson -moduleName $moduleName -modulesUrl $modulesUrl `
-properties @{DestinationPath = 'C:\test'} -configurationName $ConfigurationName -WmfVersion '4.0' -Verbose
Write-Verbose -Message "PublicConfigurationJson: $PublicConfigurationJson" -Verbose
$vm = get-azurevm -ServiceName $serviceName -Name $vmName
$vm = Set-AzureVMExtension `
-VM $vm `
-Publisher $publisher `
-ExtensionName 'DSC' `
-Version $dscVersion `
-PublicConfiguration $PublicConfigurationJson `
-ForceUpdate
$vm | Update-AzureVM
After the VM is finished update, you should have a WMF 4 VM. I’ll have a follow-up blog on how to do this in ARM.
I have published these samples to GitHub as a working script. Just update the, Service Name, etc. and run the script in the Azure PowerShell SDK.
Notes
Windows Server 2016 Technical Preview has the equivalent of WMF 5 already installed. Therefore, specifying WMF 4 for this OS is not a valid option.