Author Posts

September 10, 2018 at 1:25 pm

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

September 10, 2018 at 1:35 pm

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

 

September 10, 2018 at 1:45 pm

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'))]"
]

 }

September 10, 2018 at 1:59 pm

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')]"
          }
        }
      }
    }

September 10, 2018 at 2:50 pm

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.

September 10, 2018 at 2:52 pm

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

September 10, 2018 at 3:18 pm

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.

 

September 10, 2018 at 4:00 pm

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
    }

September 10, 2018 at 4:06 pm

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

September 10, 2018 at 4:58 pm

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

September 10, 2018 at 5:06 pm

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.

September 10, 2018 at 5:29 pm

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.

September 10, 2018 at 5:33 pm

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')]"
              }
            }
          }
        }
      ]
    }

September 10, 2018 at 5:52 pm

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.

September 10, 2018 at 5:55 pm

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

September 10, 2018 at 7:22 pm

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?

 

September 11, 2018 at 2:02 pm

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

September 11, 2018 at 4:06 pm

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

September 14, 2018 at 12:15 pm

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
}]
}
}
}

}

September 14, 2018 at 12:21 pm

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.

September 14, 2018 at 1:44 pm

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. ¯\_(ツ)_/¯