Have you been working with Azure Resource Manager (ARM) templates but found the JSON syntax difficult to work with? Do you have some awesome PowerShell skills that you’d like to put to use? Look no further! Microsoft has introduced the PSArm PowerShell module!

This new PowerShell module is designed so you can use PowerShell commands and syntax to build ARM templates. Take advantage of native PowerShell commands and logic to build ARM templates.

In this tutorial, you will learn the basics of PSArm syntax and how to use PowerShell syntax to deploy a virtual network and multiple subnets.

What is PSArm?

PSArm is an experimental project from Microsoft to use the strengths of PowerShell to make the ARM template authoring experience better. Because PSArm is currently experimental, it does not have any support or maintenance associated with it, and Microsoft could introduce breaking changes at any time. In other words, try it out, test it, but don’t currently rely on it for production.

PSArm is different from Microsoft’s other newest project called Bicep. Bicep is a standalone domain-specific language (DSL) for building ARM tempaltes. PSArm is embedded within a PowerShell script using the PowerShell module. However, both projects use the same schema backend to generate the ARM templates.

Installing PSArm PowerShell Module

PSArm is available for installation through the PowerShell Gallery and requires a minimum version of PowerShell 5.1. You install it as you would any other PowerShell Gallery module using the Install-Module command. However, since the module is in alpha, you add the -AllowPrelease parameter, like so:

Install-Module -Name PSArm -AllowPrelease

Understand Structure and Syntax

PSArm templates are written just like any other PowerShell script and have the extension .psarm.ps1. Within the PowerShell file, you define the Azure resources inside an Arm block using curly brackets, like so:

Arm {}

Within the Arm block, you start defining resources using the Resource keyword. Following the keyword are the resource attributes, such as:

  • Name
  • Namespace, e.g. ‘Microsoft.Storage’ or ‘Microsoft.Network’
  • Type of resource, e.g. ‘storageAccounts’ or ‘virtualNetworks’
  • Api version
  • Location

Here’s an example of a storage account resource using the above properties as well as the kind of storage account:

Resource '<name>' -Namespace Microsoft.Storage -Type storageAccounts -ApiVersion '<version>' -Kind '<type>' -Location '<region>' {}

If you view the Microsoft.Storage storageAccounts ARM template reference, notice the PSArm template has some of the same elements that define the storage account in an ARM template. Here is the equivalent definition of the above example in an ARM template:

  "name": "<name>",
  "type": "Microsoft.Storage/storageAccounts",
  "apiVersion": "<version>",
  "kind": "<type>",
  "location": "<region>"

Within the Resource definition, you define the remaining properties of the resource. These properties are the same as you would find in the properties section of an ARM template. For your storage account resource, you define the sku and access tier as well as properties like enforcing HTTPS, disabling public access, and enforcing a minimum TLS version.

ArmSku Standard_LRS
properties {
    accessTier 'Hot'
    supportsHttpsTrafficOnly $true
    allowBlobPublicAccess $false
    minimumTlsVersion 'TLS1_2'

I’m unsure why the ArmSku property cannot be placed in the resource definition or within the properties block. The ArmSku name also does not match with the ARM template reference. Other than seeing this example in the official GitHub repository, I’m unsure as to how you would discover how to define this property.

Here is what the full storage account definition looks like with some example values:

Arm {
    Resource 'armdemo' -Namespace Microsoft.Storage -Type storageAccounts -ApiVersion 2021-01-01 -Kind StorageV2 -Location 'westus2' {
        ArmSku Standard_LRS
        properties {
            accessTier 'Hot'
            supportsHttpsTrafficOnly $true
            allowBlobPublicAccess $false
            minimumTlsVersion 'TLS1_2'

Check out my GitHub repository for a full example using the Get-Random command to generate unique storage account name.

JeffBrownTech / psarm-examples / storage-account / basic-storage-account.psarm.ps1

Converting PSArm PowerShell to ARM Template

The PSArm PowerShell module contains the Publish-PSArmTemplate command for converting the .psarm.ps1 file to an ARM template. This command is the key command for executing the conversion process. The command uses the -Path parameter and recursively collects any .psarm.ps1 files to build the ARM template.

By default, the Publish-PSArmTemplate command outputs the new ARM template file as template.json. You can specify the output file name using the -OutFile parameter. If the output file already exists, use the -Force parameter to overwrite the file.

The Publish-PSArmTemplate command only writes the resulting ARM template file to disk. It does not perform the deployment to Azure. To deploy the resulting file, use the corresponding Azure PowerShell New-AzResourceGroupDeployment command or Azure CLI az group deployment command.

To see the resulting ARM template in JSON format for the storage account example, check out the file in my GitHub repository:

JeffBrownTech / psarm-examples / storage-account / basic-storage-account_arm.json

Tutorial: Deploying Virtual Networks and Subnets

In this tutorial, you will build a PSArm PowerShell template for deploying a virtual network and multiple subnets. I chose this example to demonstrate how you can incorporate native PowerShell commands to generate dynamic names and multiple resources.


For this tutorial, you will need the following:

  • Azure subscription where you can deploy resources.
  • A resource group. This tutorial uses a resource group named psarm-rg and all resources are deployed to the WestUS2 region.
  • The PowerShell Az module installed and logged into Azure.
  • A way to create and edit PowerShell script files.

Create the PSArm Template Script

First, create a file named vnets-and-subnets.psarm.ps1. Next, add the following code to the file. The code includes several variables for defining the virtual network and subnet. Comments are included inline for explaining each portion.

Convert the PSArm Template

With the deployment script create, convert the file to an ARM JSON template using the Publish-PSArmTemplate command. Use the -Path parameter to specify the PSArm PS1 file, and use the -OutFile to give the ARM template a specific filename. If the file already exists, don’t forget to add the -Force parameter to overwrite it.

Publish-PsArmTemplate -Path vnets-and-subnets.psarm.ps1 `
    -OutFile vnets-and-subnets.json

Deploy the Converted ARM Template

In Azure PowerShell, use the New-AzResourceGroupDeployment command to create a deployment using the ARM template. Specify the resource group name and the convert ARM template file from the previous step. Add -Verbose to examine the deployment’s progress.

New-AzResourceGroupDeployment -ResourceGroupName psarm-rg `
    -TemplateFile vnets-and-subnets.json

Learn more about different ARM template deployments modes in my article Working with ARM Template Deployment Modes!

Once the deployment finishes, log into the Azure Portal to verify the virtual network and its subnets were deployed.

verify psarm deployment
Verifying resource deployment in the Azure portal

Congratulations, you (hopefully!) just deployed your first PSArm template to Azure. Well, really, you converted a PSArm template to ARM JSON format and deployed it, but hopefully you can see the benefits to writing the resources using this new syntax.

Next Steps

To see more examples of how to author PSArm templates, check out the examples folder in the official PSArm GitHub repository. See how you can incorporate PowerShell parameters into authoring the templates and add resource dependencies. I will also continue to add examples to my psarm-examples repository.

Leave a Reply