PowerShell Module AzPolicyTest V2.0 Released
Introduction
I created the PowerShell module AzPolicyTest (GitHub, PowerShellGallery) back in 2019. This module provides a list of Pester tests can be used to validate the Azure Policy and Initiative definitions. It can also be used in your IaC pipelines. I have previously blogged about this tool in the blog post Deploying Azure Policy Definitions via Azure DevOps (Part 2).
The initial version 1.0 was developed using Pester v4. It has been 5 years and it has stopped working long time ago due to the breaking changes introduced in Pester v5. On the other hand, a lot of new capabilities have been introduced in Azure Policy since 2019. I have been wanting to update this module for a long time, but I just never got around to it.
My intention for creating this module is to collect all the best practices and lesson learned from the field and put them into a set of Pester tests. I wanted to make it easy for anyone to validate their policy definitions and initiatives before deploying them (the shift-left approach). Some of these tests addressed issues that a normal Bicep template validation would not catch and are can only be identified during the deployment phase (for example, the mode value is case sensitive and it must be using the pascaleCase format? All and Indexed are accepted but all or indexed are not?).
I have manage to spend a day to update the module to use Pester v5 and also added a few new tests to cover some of the new Azure Policy capabilities. The new version 2.0 has been released to PowerShell Gallery. You can install it using the following command:
Install-Module -Name AzPolicyTest -Force
You can use the following commands to run the tests:
Invoke tests for Policy Definitions:
#import the module if required
import-module AzPolicyTest
# Test a single policy definition file without generating the test results output file
Test-AzPolicyDefinition -Path "path-to-policy-definition-json-file.json" -OutputFile "C:\Temp\MyTestResult.xml"
# Test all policy definition json files in the directory and sub directories and store the test results in a file
Test-AzPolicyDefinition -Path "directory-path" -OutputFile "./policy.tests.xml"
Invoke tests for Policy Initiatives:
#import the module if required
import-module AzPolicyTest
# Test a single policy initiative file without generating the test results output file
Test-AzPolicySetDefinition -Path "path-to-policy-definition-json-file.json" -OutputFile "C:\Temp\MyTestResult.xml"
# Test all policy initiative json files in the directory and sub directories and store the test results in a file
Test-AzPolicySetDefinition -Path "directory-path" -OutputFile "./policy.tests.xml"

What’s Included in AzPolicyTest v2.0
The following Tests are included in the module:
Policy Definition Tests:
- Policy definition nameelement should exist
- Policy definition propertieselement should exist
- namevalue must not be null
- namevalue must not contain spaces
- displayNameelement should exist
- displayNamevalue must not be null
- descriptionelement should exist
- descriptionvalue must not be null
- metadataelement should exist
- metadatamust contain- Categoryelement
- metadatamust contain- versionelement
- versionvalue must be a valid semver version
- modeelement should exist
- modeelement must have a valid value
- parameterselement should exist
- parameterselement must have at least one item
- policyRuleelement should exist
- policyRuleelement must have a- ifand- thenchild element
- The type for each parameter must be a valid data type
- Each parameter must have a display name and description
- The policy effect must be parameterised
- The parameterised policy effect should only contain valid effects
- The parameterised policy effect should contain Disabledeffect as one of the allowed values
- If the parameterised policy effect contains Audit, then it should also containDenyand vice versa
- The parameterised policy effect should have a default value
- DeployIfNotExists,- Modifyand- AuditIfNotExistspolicy definitions should contain a- detailselement
- DeployIfNotExistsand- AuditIfNotExistspolicy definitions should contain a- existenceConditionelement
- DeployIfNotExistsand- AuditIfNotExistspolicy definitions should contain a- evaluationDelayelement
- DeployIfNotExistspolicy definition should contain a- deploymentelement
- DeployIfNotExistspolicy should set the deployment mode to- Incremental
- DeployIfNotExistsand- Modifypolicies should contain a- roleDefinitionIdselement
- At least one role definition ID should be specified for the DeployIfNotExistsandModifypolicies
- The ARM template embedded in the DeployIfNotExistspolicy should have a valid schema
- The ARM template embedded in the DeployIfNotExistspolicy should have a valid contentVersion
- The ARM template embedded in the DeployIfNotExistspolicy should have aparameters,variables,resourcesandoutputselements
- Modifypolicies should contain a- conflictEffectelement and it must have a valid value
- Modifypolicies must have an- operationselement
Policy Set Definition (Initiative) Tests:
- Policy Initiative definition nameelement should exist
- Policy Initiative definition propertieselement should exist
- namevalue must not be null
- namevalue must not contain spaces
- displayNameelement should exist
- displayNamevalue must not be null
- descriptionelement should exist
- descriptionvalue must not be null
- metadataelement should exist
- metadatamust contain- Categoryelement
- metadatamust contain- versionelement
- versionvalue must be a valid semver version
- policyDefinitionselement must exist and must contain at least one item
- policyDefinitionGroupselement must exist and must contain at least one item
- The type for each parameter must be a valid data type
- Each parameter must have a display name and description
- Each member policy must have the policyDefinitionIdandpolicyDefinitionReferenceIdelements
- The policyDefinitionIdandpolicyDefinitionReferenceIdelements for each member policy must have a valid value
- Each member policy must have a parameterselement
- Each member policy must have a groupNameselement
- The groupNameselement for each member policy must have at least one item
Json File Tests:
- The specified value for the pathparameter must contain at least one Json file
- The Json file can be correctly parsed
Conclusion
I have also bumped the minimum required PowerShell version to v7.0.0 and Pester module version to v5.5.0. Therefore you will no longer be able to use this module in the legacy Windows PowerShell (v5) environment (and if you are still using Windows PowerShell, you should really stop doing that!).
I have in included few policy and initiative definitions that I used for testing the PowerShell module. you can find them in the GitHub repo under the test_definitions folder.
Lastly, I wanted to mention that I was thinking about adding additional tests to validate the policy definition json file against the official JSON schema for Azure policy definitions. However I quickly scrapped the idea due to few limitations:
- The latest official schema I was able to find was dated back to Oct 2020, and it was created using Json schema draft-4 format. Starting for the most recent PowerShell release (v7.4.1), the Test-Jsoncmdlet has been updated to use the latest Json schema draft-7 format (breaking changes in PowerShell 7.4.1). Therefore the official schema for Azure policy definitions is no longer compatible with the latestTest-Jsoncmdlet.
- The official schema only covered the policyRulesection of the policy definition, and there is no schema for the policy initiatives.
- The Json schema is useless when you have parameterised values (such as policy effects). For example, the effect value [parameters('effect')]is not a valid value according to the schema, but it is a valid in the policy definition as long as the respective parameter is correctly defined.
If you have any suggestions or feedback, please feel free to raise an issue in the GitHub repo or each out to me on social media. I hope you find this module useful.
 
      
    
Leave a comment