Arm templates – Importing modules from the Azure Automation gallery

2017, Nov 27    

Powershell modules in Azure Automation

In this post we’re going to look at referencing Powershell modules from the gallery, in your own Arm templates. This will save having manual steps to complete after your Azure Automation Account has been deployed.
If you are looking to package up your own modules, then this guide is not for you.


Using ARM templates to deploy any kinds of infrastrure is foundational when it comes to cloud skills.
As part of an ARM template i’ve been creating; I’m wanting to deploy an Azure Automation Account, fully configured to be able to domain join VM’s. A good first step in creating an ARM template is to manually create the infrastructure in the Azure Portal and copy out the Automation Script before neatening up. Unfortunately this doesn’t work so well with several of the assets in an Automation Account, modules being the first issue.

I tend to heavily use Modules from the gallery, but it’s a little akward in inserting them into an ARM template. The Automation Script generated in Azure offers you something like this;

{
            "comments": "Generalized from resource: '/subscriptions/2d5bb2c8-8be8-4539-b48f-fbfd86852fa9/resourcegroups/DSCPlay/providers/Microsoft.Automation/automationAccounts/dscauto/modules/xDSCDomainjoin'.",
            "type": "Microsoft.Automation/automationAccounts/modules",
            "name": "[concat(parameters('automationAccounts_dscauto_name_1'), '/', parameters('modules_xDSCDomainjoin_name'))]",
            "apiVersion": "2015-10-31",
            "scale": null,
            "properties": {
                "isGlobal": false,
                "version": "1.1",
                "sizeInBytes": 0
            },
            "dependsOn": [
                "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccounts_dscauto_name_1'))]"
            ]
        },

Which if you look at it, seems reasonable. Its type has been set to Microsoft.Automation/automationAccounts/modules and the version looks good. However this won’t pull down the module from the gallery.
Here’s what you need to do…

Find the Module

For me, my module is v1.1 of xDSCDomainJoin
https://www.powershellgallery.com/items?q=xDSCDomainjoin&x=16&y=18
https://www.powershellgallery.com/packages/xDSCDomainjoin/1.1

Root Template

So on this page; https://www.powershellgallery.com/packages/xDSCDomainjoin/1.1is a link to “Deploy to Azure Automation”
Clicking the link, takes you to the Azure Portal with the template pre-loaded to deploy.
https://portal.azure.com/?microsoft_azure_automation_armTemplateUrl=https%3A%2F%2Fdevopsgallerystorage.blob.core.windows.net%2Farmtemplates%2FxDSCDomainjoin%255C1.1%255CRootTemplate.json

If you extract the TemplateUrl out, and UrlDecode it, you’re left with;
https://devopsgallerystorage.blob.core.windows.net/armtemplates/xDSCDomainjoin/1.1/RootTemplate.json
When you hit this url you get prompted to download RootTemplate.zip

Once it’s downlaoded, rename the files extension back to .json from .zip
Here’s what’s inside;

{
  "$schema": "http://schemas.microsoft.org/azure/deploymentTemplate?api-version=2015-01-01#",
  "contentVersion": "1.0",
  "parameters": {
    "New or existing Automation account": {
      "type": "string",
      "allowedValues": [
        "New",
        "Existing"
      ],
      "metadata": {
        "description": "Select whether you want to create a new Automation account or use an existing account. WARNING: if you select NEW but use an Automation account name that already exists in your subscription, you will not be notified that your account is being updated. The pricing tier for the account will be set to free and any tags on the account will be erased."
      }
    },
    "Automation Account Name": {
      "type": "string",
      "metadata": {
        "description": "The module will be imported to this Automation account. If you want to import your module to an existing account, make sure the resource group matches and you have entered the correct name. The account name must be between 6 to 50 characters, and can contain only letters, numbers, and hyphens."
      }
    },
    "Automation Account Location": {
      "type": "string",
      "metadata": {
        "description": "The location to deploy the Automation account in. If you select an existing account, the location field will not be used."
      }
    }
  },
  "variables": {
    "templatelink": "[concat('https://devopsgallerystorage.blob.core.windows.net/armtemplates/xDSCDomainjoin/1.1/', parameters('New or existing Automation account'), 'AccountTemplate.json')]",
    "xDSCDomainjoin:1.1.0:Name": "xDSCDomainjoin",
    "xDSCDomainjoin:1.1.0:Uri": "https://devopsgallerystorage.blob.core.windows.net/packages/xdscdomainjoin.1.1.0.nupkg"
  },
  "resources": [
    {
      "apiVersion": "2015-01-01",
      "name": "nestedTemplate",
      "type": "Microsoft.Resources/deployments",
      "properties": {
        "mode": "incremental",
        "templateLink": {
          "uri": "[variables('templatelink')]",
          "contentVersion": "1.0"
        },
        "parameters": {
          "accountName": {
            "value": "[parameters('Automation Account Name')]"
          },
          "accountLocation": {
            "value": "[parameters('Automation Account Location')]"
          },
          "xDSCDomainjoin:1.1.0:Name": {
            "value": "[variables('xDSCDomainjoin:1.1.0:Name')]"
          },
          "xDSCDomainjoin:1.1.0:Uri": {
            "value": "[variables('xDSCDomainjoin:1.1.0:Uri')]"
          }
        }
      }
    }
  ],
  "outputs": {}
}

This is a pretty simple template that calls another template on the url held in this variable;
"templatelink": "[concat('https://devopsgallerystorage.blob.core.windows.net/armtemplates/xDSCDomainjoin/1.1/', parameters('New or existing Automation account'), 'AccountTemplate.json')]",

Because we’re going to be using this in a New Automation Account, lets compose the url properly;

https://devopsgallerystorage.blob.core.windows.net/armtemplates/xDSCDomainjoin/1.1/NewAccountTemplate.json

As parameters for this template, it passes in the Name and Uri for the xDSCDomainjoin module. We’ll come back for these variables later.

New account template

Follow the url from above; https://devopsgallerystorage.blob.core.windows.net/armtemplates/xDSCDomainjoin/1.1/NewAccountTemplate.json
You’ll be prompted to download NewAccountTemplate.zip. Again, rename the extension back to .json.
Open the file and you’ll see;

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0",
  "parameters": {
    "accountName": {
      "type": "string"
    },
    "accountLocation": {
      "type": "string"
    },
    "xDSCDomainjoin:1.1.0:Name": {
      "type": "string"
    },
    "xDSCDomainjoin:1.1.0:Uri": {
      "type": "string"
    }
  },
  "variables": {},
  "resources": [
    {
      "name": "[parameters('accountName')]",
      "type": "Microsoft.Automation/automationAccounts",
      "apiVersion": "2015-10-31",
      "location": "[parameters('accountLocation')]",
      "dependsOn": [],
      "tags": {},
      "properties": {
        "comment": "Resource defined structure",
        "sku": {
          "name": "free"
        }
      },
      "resources": [
        {
          "name": "[parameters('xDSCDomainjoin:1.1.0:Name')]",
          "type": "modules",
          "apiVersion": "2015-10-31",
          "location": "[parameters('accountLocation')]",
          "dependsOn": [
            "[concat('Microsoft.Automation/automationAccounts/', parameters('accountName'))]"
          ],
          "tags": {},
          "properties": {
            "contentLink": {
              "uri": "[parameters('xDSCDomainjoin:1.1.0:Uri')]"
            }
          }
        }
      ]
    }
  ],
  "outputs": {}
}

Snipping the bits that matter

It’s simply the module resource that we want to steal to lift into our Automation Account template. Grab that definition, and the two variables from the last file and you have enough to plug into your own Arm template.

<br /> "xDSCDomainjoin:1.1.0:Name": "xDSCDomainjoin",<br /> "xDSCDomainjoin:1.1.0:Uri": "https://devopsgallerystorage.blob.core.windows.net/packages/xdscdomainjoin.1.1.0.nupkg"<br />

<br /> {<br /> "name": "[parameters('xDSCDomainjoin:1.1.0:Name')]",<br /> "type": "modules",<br /> "apiVersion": "2015-10-31",<br /> "location": "[parameters('accountLocation')]",<br /> "dependsOn": [<br /> "[concat('Microsoft.Automation/automationAccounts/', parameters('accountName'))]"<br /> ],<br /> "tags": {},<br /> "properties": {<br /> "contentLink": {<br /> "uri": "[parameters('xDSCDomainjoin:1.1.0:Uri')]"<br /> }<br /> }<br /> }<br />