Azure DSC extention via ARM template.

Welcome Forums DSC (Desired State Configuration) Azure DSC extention via ARM template.

This topic contains 21 replies, has 2 voices, and was last updated by

 
Participant
2 months ago.

  • Author
    Posts
  • #111392

    Participant
    Points: 21
    Rank: Member

    Hi, hoping someone can help me here.

    I was receiving a parameter not found error for NodeConfigurationName prior to this so I removed it from the template. Now I'm getting another for AllowModuleOverwrite.

    Last attempt to process request for sequence number 0 failed with error A parameter cannot be found that matches parameter name 'AllowModuleOverwrite'.\n\nAnother common error is to specify parameters of type PSCredential without an explicit type. Please be sure to use a typed parameter in DSC Configuration, for example:\n\n    configuration Example {\n        param([PSCredential] $UserAccount)

    According to this documentation both parameters exist.
    https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/dsc-template

  • #111394

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    Hey there Dan.  Can you share the code on how you're attempting to register the node?

     

    • #111422

      Participant
      Points: 21
      Rank: Member

      Here is the DSC section. Thanks for looking.

      {
      
      "type": "Microsoft.Compute/virtualMachines/extensions",
      "name": "[concat(parameters('virtualMachineName'), '/Microsoft.Powershell.DSC')]",
      "apiVersion": "2017-12-01",
      "location": "eastus2",
      "tags": {
      "AutomationAccountARMID": "/subscriptions/..."
      },
      "scale": null,
      "properties": {
      "autoUpgradeMinorVersion": true,
      "settings": {
      "Properties": [
      {
      "Name": "RegistrationKey",
      "Value": {
      "UserName": "PLACEHOLDER_DONOTUSE",
      "Password": "PrivateSettingsRef:registrationKeyPrivate"
      },
      "TypeName": "System.Management.Automation.PSCredential"
      },
      {
      "Name": "RegistrationUrl",
      "Value": "https://eus2-agentservice-prod-1.azure-automation.net/accounts/...",
      "TypeName": "System.String"
      },
      {
      "Name": "ConfigurationMode",
      "Value": "applyAndMonitor",
      "TypeName": "System.String"
      },
      {
      "Name": "ConfigurationModeFrequencyMins",
      "Value": 15,
      "TypeName": "System.Int32"
      },
      {
      "Name": "RefreshFrequencyMins",
      "Value": 30,
      "TypeName": "System.Int32"
      },
      {
      "Name": "RebootNodeIfNeeded",
      "Value": true,
      "TypeName": "System.Boolean"
      },
      {
      "Name": "ActionAfterReboot",
      "Value": "continueConfiguration",
      "TypeName": "System.String"
      },
      {
      "Name": "AllowModuleOverwrite",
      "Value": false,
      "TypeName": "System.Boolean"
      }
      ],
      "modulesUrl": "https://xxx.blob.core.windows.net/dscconfigs/xxx_servers.ps1.zip",
      "configurationFunction": "[parameters('extensions_Microsoft.Powershell.DSC_configurationFunction')]",
      "SasToken":"xxxsastokenxxx"
      },
      "publisher": "Microsoft.Powershell",
      "type": "DSC",
      "typeHandlerVersion": "2.76",
      "protectedSettings": {
      "Items": {
      "registrationKeyPrivate": "xxxregistrationkeyxxx"
      }
      }
      },
      "dependsOn": [
      "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]"
      ]
      
       }
  • #111428

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    How were you passing the nodeConfigurationName?  I can share with you a working example of mine.  Perhaps try matching it up and see if it helps?

    Variable Set:

        "dscLocalConfigurationManager": {
          "rebootNodeIfNeeded": true,
          "configurationMode": "ApplyAndAutocorrect",
          "actionAfterReboot": "ContinueConfiguration",
          "allowModuleOverwrite": true,
          "dscExtensionVersion": "2.72",
          "modulesURI": "https://azurestorage.blob.core.windows.net/automationdscpreview/RegistrationMetaConfigV2.zip",
          "configurationFunction": "RegistrationMetaConfigV2.ps1\\RegistrationMetaConfigV2"
        },

    Resource Code:

        {
          "type": "Microsoft.Compute/virtualMachines/extensions",
          "apiVersion": "2015-06-15",
          "copy": {
            "count": "[variables('VMConfigReference').assignedConfig.instanceCount]",
            "name": "assignedConfigDSCBaseConfig"
          },
          "name": "[concat(variables('VMConfigReference').assignedConfig.Name,0,copyIndex(1),'/assignedConfigBaseDSC')]",
          "dependsOn": [
            "[resourceId('Microsoft.Compute/virtualMachines',concat(variables('VMConfigReference').assignedConfig.Name,0,copyIndex(1)))]"
          ],
          "location": "[resourceGroup().Location]",
          "properties": {
            "type": "DSC",
            "publisher": "Microsoft.Powershell",
            "typeHandlerVersion": "[variables('dscLocalConfigurationManager').dscExtensionVersion]",
            "settings": {
              "modulesUrl": "[variables('dscLocalConfigurationManager').modulesURI]",
              "configurationFunction": "[variables('dscLocalConfigurationManager').configurationFunction]",
              "Properties": [
                {
                  "Name": "RegistrationKey",
                  "Value": {
                    "UserName": "PLACEHOLDER_DONOTUSE",
                    "Password": "PrivateSettingsRef:registrationKeyPrivate"
                  },
                  "TypeName": "System.Management.Automation.PSCredential"
                },
                {
                  "Name": "RegistrationUrl",
                  "Value": "[parameters('automationRegistrationUrl')]",
                  "TypeName": "System.String"
                },
                {
                  "Name": "NodeConfigurationName",
                  "Value": "[variables('VMConfigReference').assignedConfig.dscConfiguration]",
                  "TypeName": "System.String"
                },
                {
                  "Name": "ConfigurationMode",
                  "Value": "[variables('dscLocalConfigurationManager').configurationMode]",
                  "TypeName": "System.String"
                },
                {
                  "Name": "RebootNodeIfNeeded",
                  "Value": "[variables('dscLocalConfigurationManager').rebootNodeIfNeeded]",
                  "TypeName": "System.Boolean"
                },
                {
                  "Name": "ActionAfterReboot",
                  "Value": "[variables('dscLocalConfigurationManager').actionAfterReboot]",
                  "TypeName": "System.String"
                },
                {
                  "Name": "AllowModuleOverwrite",
                  "Value": "[variables('dscLocalConfigurationManager').allowModuleOverwrite]",
                  "TypeName": "System.Boolean"
                }
              ],
              "wmfVersion": "5.1"
            },
            "autoUpgradeMinorVersion": true,
            "protectedSettings": {
              "Items": {
                "registrationKeyPrivate": "[parameters('automationRegistrationKey')]"
              }
            }
          }
        }
  • #111442

    Participant
    Points: 21
    Rank: Member

    Thanks. I'm guessing the api version was the issue.

    I took a stab at updating my code to the most current format but I can't make sense of the instructions.

    In some cases they use protectedsettings.items but in others they just put the values under protectedsettings.

  • #111443

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    Could very well be. I've also used 2017-03-30 in the same template (I should probably update them all), but I haven't tried using the latest one (2017-12-XX).

  • #111457

    Participant
    Points: 21
    Rank: Member

    oh my.. I'm gonna lose it 🙂  Now I'm getting this.

    The term 'Get-AutomationPSCredential' is not recognized as the name of a cmdlet, function, script file, or operable program.

    If I connect the machine manually using the portal and assign the same configuration, this works fine.

     

  • #111463

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    Get-AutomationPSCredential doesn't exist locally. You'll leverage it in your configuration. When you deploy the config it'll grab the cred with that cmdlet.

    Configuration SomeComposite{
    
        Param(
    
            [parameter(Mandatory=$true)][string]$adminAccount
    
    
        )
    
        Import-DscResource -ModuleName 'xNetworking' -ModuleVersion '5.6.0.0'
    
        $AdminCred = Get-AutomationPSCredential -Name $adminAccount
    
    
        Node $AllNodes.NodeName
        {
            
        }
        Node ($AllNodes.Where{$_.Role -eq "TargetNode"}).NodeName
        {
            PSDscRunAsCredential = $AdminCred
        }
    
  • #111467

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    FYI – I did a blog series on this. You might find some of the info helpful. 🙂

    https://www.google.com/search?q=powershell.org+using+azure+desired+state+configuration&oq=powershell.org+using+azure+desired+state+configuration&aqs=chrome..69i57.12299j1j7&sourceid=chrome&ie=UTF-8

  • #111473

    Participant
    Points: 21
    Rank: Member

    Ok, so when you compile the configuration that's turned into the credential object.

    How would we do this when copying just when publishing the configuration to blob storage?

    Dan

  • #111475

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    Ahhh. You're pushing the config. Have you looked at leveraging Azure Automation DSC? You can store the compiled mofs in an encrypted store and assign them out to your nodes for free (Azure nodes).

    If you're storing the config in blob store and pushing it to a machine, you'll have to pass the credential during the template deployment. I _might_ still have a template example laying around. I'll have to look for it.

  • #111478

    Participant
    Points: 21
    Rank: Member

    I was looking to incorporate the dsc registration process inside the arm template for building vm's so the build person doesn't have to connect and assign the configurations. Though it does seem like less work to give them the instructions on how to do it at this point:-)

    I've seen a few posts on leveraging azure keyvaults but I was hoping to use the already stored credentials stored in the credential section of the automation account.

  • #111481

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    Yeah. The only time I did it with push in a template was by adding the extension as a child resource. You should be able to use it as a standalone resource though. Example code:

        {
          "apiVersion": "2015-06-15",
          "type": "Microsoft.Compute/virtualMachines",
          "location": "[resourceGroup().location]",
          "name": "[variables('CMPrimaryName')]",
          "dependsOn": [
            "[resourceId('Microsoft.Storage/storageaccounts',variables('StorageAccountName'))]",
            "[resourceId('Microsoft.Network/networkInterfaces','cmprinif')]"
          ],
          "properties": {
            "hardwareProfile": {
              "vmSize": "[variables('CMPrimaryVMSize')]"
            },
            "osProfile": {
              "computerName": "[variables('CMPrimaryName')]",
              "adminUsername": "[variables('adminUserName')]",
              "adminPassword": "[variables('adminPassword')]"
            },
            "storageProfile": {
              "imageReference": {
                "publisher": "[variables('imagePublisher')]",
                "offer": "[variables('imageOffer')]",
                "sku": "[variables('WindowsOSVersion')]",
                "version": "latest"
              },
              "osDisk": {
                "name": "[concat(variables('CMPrimaryName'),'-osdisk')]",
                "vhd": {
                  "uri": "[concat('http://',variables('StorageAccountName'),'.blob.core.windows.net/vhds/',variables('CMPrimaryName'),'-osdisk.vhd')]"
                },
                "caching": "ReadWrite",
                "createOption": "FromImage"
              },
              "dataDisks": [
                {
                  "name": "[concat(variables('CMPrimaryName'),'-data-disk1.vhd')]",
                  "vhd": {
                    "uri": "[concat('http://',variables('StorageAccountName'),'.blob.core.windows.net/vhds/',variables('CMPrimaryName'),'-data-disk1.vhd')]"
                  },
                  "caching": "None",
                  "createOption": "Empty",
                  "diskSizeGB": "1000",
                  "lun": 0
                }
              ]
            },
            "networkProfile": {
              "networkInterfaces": [
                {
                  "id": "[resourceId('Microsoft.Network/networkInterfaces','cmprinif')]"
                }
              ]
            },
            "diagnosticsProfile": {
              "bootDiagnostics": {
                "enabled": true,
                "storageUri": "[concat('http://',variables('StorageAccountName'),'.blob.core.windows.net')]"
              }
            }
          },
          "resources": [
            {
              "type": "extensions",
              "apiVersion": "2015-05-01-preview",
              "name": "[concat(variables('CMPrimaryName'),'domainjoin')]",
              "location": "[resourceGroup().location]",
              "dependsOn": [
                "[resourceId('Microsoft.Compute/virtualMachines',variables('CMPrimaryName'))]",
                "[resourceId('Microsoft.Compute/virtualMachines',variables('DCVMName'))]"
              ],
              "properties": {
                "publisher": "Microsoft.PowerShell",
                "type": "DSC",
                "typeHandlerVersion": "2.8",
                "settings": {
                  "ModulesUrl": "[concat(variables('ADAssetLocation'),'/Configuration.zip')]",
                  "ConfigurationFunction": "Configuration.ps1\\DomainJoin",
                  "Properties": {
                    "DomainName": "[variables('ADDomainName')]",
                    "AdminCreds": {
                      "UserName": "[variables('adminUserName')]",
                      "Password": "PrivateSettingsRef:adminPassword"
                    }
                  }
                },
                "protectedSettings": {
                  "Items": {
                    "adminPassword": "[variables('adminPassword')]"
                  }
                }
              }
            }
          ]
        }
    
  • #111484

    Participant
    Points: 21
    Rank: Member

    Bummer.. I like the dynamic way of storing the credentials in the automation account so the configuration script doesn't have to be modified if the credentials change. Variable would work but it'll still deploy the resources if the password supplied is wrong.

    I can use get-automationpscredential inside the configuration when deploying manually in the portal after connecting a vm and assigning a configuration.

    Choosing the vm and adding the dsc extension and supplying a configuration (zipped) does not work.

    Why these methods don't work the same is beyond me.

  • #111487

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    You can use Get-AzureRmAutomationCredential and pass the object into the template via parameter.

  • #111490

    Participant
    Points: 21
    Rank: Member

    I think I should mention I'm using the 'Templates' service within the portal.  So the process for the person building a server would be to open the shared template and click deploy. They fill out the servername and password fields and then click purchase. I guess in a sense a static arm template, we're not building a new template for each deployment.

    Does this sound like it would work with Get-AzureRmAutomationCredential?

     

  • #111548

    Participant
    Points: 21
    Rank: Member

    So the trick was to join to the domain via template vs. DSC. I'm slowly wrapping my head around this 🙂

    Now I want the dsc extension to dependon the domain join. Does this look correct?

    "[resourceId('Microsoft.Compute/virtualMachines/extensions',concat(parameters('virtualMachineName'),'extensions/joindomain'))]"

    This is the resource ID of the last machine I deployed.

    Microsoft.Compute/virtualMachines/GSS-AZURE-T7/extensions/joindomain

  • #111578

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    Thaaaat looks right? I always go with 'test it and see if it breaks' when it comes to updating my JSON templates. 😉

  • #111727

    Participant
    Points: 21
    Rank: Member

    edit.

  • #111797

    Participant
    Points: 21
    Rank: Member

    I managed to update it to the latest format and it attempts to deploy but in the VM dsc logs I see that it's not appending the sas token to the configuration url. I have a ticket open with MS but no reply for three days. Is there anything you can see wrong with this?

    {
    
    "type": "Microsoft.Compute/virtualMachines/extensions",
    "name": "[concat(parameters('vmName'),'/Microsoft.Powershell.DSC')]",
    "apiVersion": "2017-12-01",
    "location": "[resourceGroup().location]",
    "dependsOn": [
    "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('vmName'), variables('extensionname'))]"
    ],
    "properties": {
    "publisher": "Microsoft.Powershell",
    "type": "DSC",
    "typeHandlerVersion": "2.76",
    "autoUpgradeMinorVersion": true,
    "settings": {
    "wmfVersion": "latest",
    "configuration": {
    "url": "https://...storage.blob.core.windows.net/dscconfigs/servers.ps1.zip",
    "script": "servers.ps1",
    "function": "[parameters('extensions_Microsoft.Powershell.DSC_configurationFunction')]"
    },
    "protectedSettings": {
    "Items": {
    "registrationKeyPrivate": "123456"
    },
    "configurationUrlSasToken": "?sv=2017-07-29..."
    
    },
    "publicSettings": {
    "configurationArguments": [{
    "Name": "RegistrationKey",
    "Value": {
    "UserName": "PLACEHOLDER_DONOTUSE",
    "Password": "PrivateSettingsRef:registrationKeyPrivate"
    }
    },
    {
    "RegistrationUrl": "https://eus2-agentservice-prod-1.azure-automation.net/accounts/...",
    "NodeConfigurationName": "servers.localhost",
    "ConfigurationMode": "ApplyAndAutocorrect",
    "RebootNodeIfNeeded": true,
    "ActionAfterReboot": "ContinueConfiguration",
    "AllowModuleOverwrite": true
    }]
    }
    }
    }
    
    }
  • #111800

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    I don't think I've ever used that before. I'd be curious to see if someone has any example code they'd be willing to share. If I need to pull from secure blob, I usually use a PowerShell command to general the entire SAS token URL and pass it in as a parameter.

  • #111805

    Participant
    Points: 21
    Rank: Member

    This is the only way I could get the lcm options to work 🙁 The old way doesn't work for our subscription for unknown reasons. Kinda odd, I would think this would be a breaking change for other customers. Though the documentation does state that the old format is automatically converted. ¯\_(ツ)_/¯

You must be logged in to reply to this topic.