Until recently I had not used the runCommands property in Bicep. I had used the Azure Custom Script Extension for that. But now that I have used it and I am using it more and more, I wanted to share a small tip on how to use parameters in the runCommands property.

In this blog post, I will show you how to use parameters in the runCommands property in Bicep.

Prerequisites

If you want to follow along with this blog post, you’ll need the following:

  • Azure Subscription
  • Azure CLI
  • Bicep CLI
  • Visual Studio Code

Creating the resources

First we need to create some resources.

We will create

  • a virtual network
  • a subnet
  • a public IP address
  • a network interface
  • and a virtual machine.

We will use the following Bicep script to create the resources:

param location string = 'eastus'
param vmName string = 'myVM'
param adminUsername string = 'adminUser'
param adminPassword string = 'P@ssw0rd1234'

resource vnet 'Microsoft.Network/virtualNetworks@2024-05-01' = {
  name: 'myVNet'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
  }
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2024-05-01' = {
  name: 'mySubnet'
  parent: vnet
  properties: {
    addressPrefix: '10.0.0.0/24'
  }
}

resource publicIP 'Microsoft.Network/publicIPAddresses@2024-05-01' = {
  name: 'myPublicIP'
  location: location
  properties: {
    publicIPAllocationMethod: 'Dynamic'
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2024-05-01' = {
  name: 'myNIC'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'myIPConfig'
        properties: {
          subnet: {
            id: subnet.id
          }
          publicIPAddress: {
            id: publicIP.id
          }
        }
      }
    ]
  }
}

resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = {
  name: vmName
  location: location
  properties: {
    hardwareProfile: {
      vmSize: 'Standard_DS2_v2'
    }
    osProfile: {
      computerName: vmName
      adminUsername: adminUsername
      adminPassword: adminPassword
    }
    storageProfile: {
      imageReference: {
        publisher: 'MicrosoftWindowsServer'
        offer: 'WindowsServer'
        sku: '2019-Datacenter'
        version: 'latest'
      }
      osDisk: {
        createOption: 'FromImage'
        managedDisk: {
          storageAccountType: 'Standard_LRS'
        }
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

Save the script to a file (i.e ‘create-resources.bicep’) and deploy it with the following command:

az deployment group create --resource-group <resource-group> --template-file .\resources\create-resources.bicep

Using the runCommands property

To demonstrate the runCommands property, we will add the following code to the Bicep file:

param location string = 'eastus'
param vmName string = 'myVM'

resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = {
  name: vmName
  location: location
}

resource runCommands 'Microsoft.Compute/virtualMachines/runCommands@2024-07-01' = {
  name: '${vm.name}-runCommands'
  location: location
  parent: vm
  properties: {
    source: {
      script: '''
        if(-not (Test-Path -Path "C:\Temp")) {
          New-Item -Path "C:\Temp" -ItemType Directory
        }
        Write-Output "Lorem ipsum dolor sit amet, consectetur adipiscing elit." | Out-File -FilePath C:\Temp\lorem.txt
      '''
    }
    timeoutInSeconds: 900
  }
}

Save the script to a file (i.e ‘create-file1.bicep’) and deploy it with the following command:

az deployment group create --resource-group <resource-group> --template-file .\resources\create-file1.bicep

We should end up with this:

File1 created

This file deploys a Windows and write some static text to a file. The command is hardcoded in the Bicep file.

But what if we want to use parameters in the runCommands property?

Using parameters in the runCommands property

To use parameters in the runCommands property, we need to create a parameter and use that parameter in the runCommands property. The parameter will be a string and will contain the command we want to run.

The Bicep file will look like this:

param location string = 'eastus'
param vmName string = 'myVM'

param textValue string = 'Hello, World!'
param filePathLocation string = 'C:\\Temp\\output.txt'

resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = {
  name: vmName
  location: location
}

resource runCommands 'Microsoft.Compute/virtualMachines/runCommands@2024-07-01' = {
  name: '${vm.name}-runCommands'
  location: location
  parent: vm
  properties: {
    parameters: [
      {
        name: 'FilePath'
        value: filePathLocation
      }
      {
        name: 'Text'
        value: textValue
      }
    ]
    source: {
      script: '''
        param (
          [string]$FilePath,
          [string]$Text
        )

        if(-not (Test-Path -Path "$(Split-Path -Path $FilePath -Parent)")) {
          New-Item -Path "$(Split-Path -Path $FilePath -Parent)" -ItemType Directory
        }
        
        Write-Output $Text | Out-File -FilePath $FilePath
      '''
    }
    timeoutInSeconds: 900
  }
}

We added two parameters to the Bicep file. The textValue parameter is a string and contains the text we want to write to the file. The filePathValue parameter is also a string and contains the path to the file we want to write to.

We also added the parameters property to the runCommands property. This property contains an array of parameters. Each parameter has a name and a value. The name is the name of the parameter in the script and the value is the value of the parameter.

We also changed the script property to use the parameters. We added a param block to the script and used the parameters in the script.

Save the script to a file (i.e ‘create-file2.bicep’) and deploy it with the following command:

az deployment group create --resource-group <resource-group> --template-file .\resources\create-file2.bicep

We should end up with this:

File2 created

In this case we did not give the az command the parameters. We could have done that with the following command:

az deployment group create --resource-group <resource-group> --template-file .\resources\create-file2.bicep --parameters textValue='How cool to use parameters like this!' filePathLocation='C:\\Temp\\output2.txt'

In this example the result should look like this:

File2 created with parameters

Conclusion

In this blog post, I showed you how to use parameters in the runCommands property in Bicep. By using parameters, you can make your Bicep files more flexible and reusable. You can use parameters to pass values to the runCommands property and use those values in the script.

I hope this blog post was helpful to you. If you have any questions or comments, please leave them below. I would love to hear from you.