Using Bicep’s loadTextContent() for Azure Image Builder

3 minute read

Recently I started using Azure Image Builder together with Azure Biceps ability to load a script from a separate file. In this blog I will show you how to deploy & build a simple image template and distribute it to either a VHD or Shared Image Gallery.

Before you start make sure you have the latest Azure Bicep and Az.PowerShell module or Azure CLI installed and have access to an Azure subscription / Resource Group to deploy and build the templates.

In this example I am going to use Chocolatey to install some tools and use the Install-WindowsFeature cmdlet for installing RSAT on a Windows Server 2019 system. For me this sounds like the typical jumphost configuration.

All example files can be found on my GitHub for reference, so feel free to adjust them to your needs or clone to your pc for usage throughout this blog.

To use Azure Image Builder we need a User Assigned Identity that has access to the template (or resource group) in which this template is going to be deployed. In this example I use the Contributor role, if you want to use least privilege you can create a custom role, see Microsoft docs for more information.

In my repository I have one main.bicep, which orchestrates the deployment and uses the files in the subfolders (modules, scripts)

  1. It will create a resource group.
  2. It will create the required User Assigned Managed Identity.
  3. It will assign the User Assign Managed Identity the Contributor role on the earlier deployed Resource Group.
  4. It will deploy the Image Template to Azure.

We can inspect the jumphost-config.ps1 file, which simply runs a couple of PowerShell cmdlets to install software with Chocolatey. We could copy this in the bicep file directly, which is OK.. but how about importing the file into the bicep at compile time and enjoy Intellisense from our IDE while authoring the PowerShell script? We can do this by using the loadTextContent() function in Bicep.

In the module folder, file: vm-image-template-pwsh.bicep we see the following variable, it will simply import the contents of the file into the bicep file (red text):

var inlineScript = [
  {
    type: 'PowerShell'
    name: 'PowerShellScript'
    runAsSystem: true
    runElevated: true
    inline: [
     <strong> <span class="has-inline-color has-accent-color">loadTextContent('../scripts/jumphost-config.ps1')</span></strong>
    ]
    validExitCodes: [
      0
      3010 // Reboot required
    ]
  }
]

Unfortunately we can’t set the name of the file as a parameter due to the fact that it would be unknown which file to load at compilation time. (More info on why can be found on Github Issue for Azure Bicep)

Note: for the full spec of the arm template possibilities for Azure Image Builder see this page.

To deploy the bicep files (and end up with a usable template in Azure) simply run the following line of code or provide your own parameter names inline or using a JSON parameter file.

Azure PowerShell

New-AzDeployment -Name "Azure-Image-Builder-Deployment" -Location "WestEurope" -TemplateFile .\main.bicep

Azure CLI

az deployment sub create --name "Azure-Image-Builder-Deployment" --location "WestEurope" --template-file ".\main.bicep"

If everything was successful you should end up with the aforementioned resources: A Resource Group with a Managed Identity & Image Template resource.

</figure>

If we inspect the “Export Template” section of the Image Template you should see the contents of the PowerShell script, ready to be executed.

<figcaption>Contents of the Export Template section</figcaption></figure>

To start the build click on the Image Template resource and hit the build button. In a next blog I will show you how you can create a VM from this!

Note: At this time we cannot update / replace an existing Image Template file in Azure. If you want to run the template multiple times remove the Image Template in Azure or change the name of the ImageTemplate.

Comments