Blog Post

Azure Governance and Management Blog
4 MIN READ

Open Sourcing the Azure Policy Linter!

stevenbucher's avatar
stevenbucher
Icon for Microsoft rankMicrosoft
Sep 28, 2026

Today we’re excited to share that the Azure Policy Linter is now open source on GitHub: github.com/Azure/azure-policy-linter. It’s a command-line linter for Azure Policy definitions that surfaces known issues, gotchas, and best practices that you can run when authoring your policy definition and before you assign a policy to your environment.

Why we built it

Writing a good policy is hard. It requires deep knowledge of the policy language, how each effect behaves, and the API surface of every resource type you’re targeting. 

The linter codifies that expertise into a set of automated rules. Instead of learning every gotcha the hard way, you get actionable error, warning, and informational findings on your specific policy definition immediately.

The linter fits naturally into the way policy authors already work:

  • Shift governance mistakes left. Catch problems on your laptop or in CI, long before a bad policy reaches a subscription and blocks legitimate deployments or produces misleading compliance results.
  • Lint one file or a whole library. Point it at a single definition, or run it across up to 1,000 files in one parallelized pass with file-specific results.
  • Get machine-readable output. Emit findings to the console for humans, or to JSON (--output results.json) so you can gate pull requests and pipelines.
  • Tune it to your scenario. Rules are grouped into rule sets. The default rule set covers general-purpose checks; you can list available sets (--list-rule-sets), apply a specific one, or combine several (--rule-set <name> --rule-set default).
  • Understand every finding. Each rule ships with its own documentation page under docs/Rules/, explaining the why, plus violation and corrected examples.

Installing NuGet

The linter is now published on NuGet. Install the Microsoft.Azure.Policy.PolicyLinter.Cli CLI as a global .NET tool by running

dotnet tool install --global Microsoft.Azure.Policy.PolicyLinter.Cli

Then invoke it as

policylinter

To consume the linter as a library instead, reference the Microsoft.Azure.Policy.PolicyLinter.Core package.

 

Installing from source

You can also run directly from source. Clone the repo, build the solution, and invoke the CLI with dotnet run:

git clone https://github.com/Azure/azure-policy-linter.git
cd azure-policy-linter
dotnet build src/dirs.proj --configuration Release
dotnet run --project src/PolicyLinter.Cli -- <path-to-policy-json>

Running the linter

Once installed, point policylinter at one or many definitions:

# Single file
policylinter c:\path\to\policyDefinition.json

# Multiple files (up to 1,000 in a single, parallelized run)
policylinter policy1.json policy2.json --output results.json

# See which rule sets are available, then pick one
policylinter --list-rule-sets
policylinter policy.json --rule-set <RuleSetName> --rule-set default

Run policylinter --help at any time for the full list of options.

One great use case is to ask GitHub Copilot to run the policy linter against the policy definition you are authoring, and it can read the output and help you fix your definition to meet all the rules suggestions!

Policy linter rules

The linter’s real value is in its rule catalog. Every rule has its own documentation page with the rationale plus violation and corrected examples. Here are few of the more common rules:

1. All parameter references must resolve (Error)

Every parameters('...') reference must point to a parameter actually declared in the policy. A single typo — referencing efect when you declared effect — means the policy fails to deploy or evaluate. This rule catches that class of showstopper bug instantly, before you ever push the definition to Azure.

2. Risky effect parameter default value (Warning)

Parameterizing the effect is a best practice — but if the effect parameter defaults to an enforcement effect like deny, modify, or deployIfNotExists, then any assignment that doesn’t explicitly override it will enforce by default. That’s rarely what the person assigning the policy expects. The rule flags risky defaults and steers you toward a safe default like audit (or no default at all).

3. Read-only field alias (Warning)

This is exactly the kind of hidden gotcha that’s almost impossible to learn from docs. If your policy keys off a field alias that maps to a read-only property, that property can’t be relied on during enforcement — callers aren’t required to send it, and providers often ignore it if they do. A deny policy built on a read-only alias may simply not work. The linter draws on the public Azure REST API specs to know which properties are read-only.

4. Broad type matching operator (Warning)

Comparing the type field with a broad operator like like, contains, or match can silently match resource types you never intended to govern. For example, "contains": "virtualMachines" matches both Microsoft.Compute/virtualMachines and .../virtualMachines/extensions. The rule pushes you toward equals (single type) or in (an explicit list) so your scope is exactly what you meant.

 

These are just a few highlights, the linter ships with many more, covering effect parameters, API-version mismatches, and readability simplifications. Browse the complete, per-rule documentation in docs/Rules/.

Don’t see a rule you need? Add your own

The rule catalog captures the gotchas we’ve hit, but you know your environment best. If there’s a check that would help your team and it isn’t there yet, the linter is designed to be extended. The repo’s Adding a linter rule section walks you through it, backed by two guides, what a good rule looks like and how rules are wired up in code. Plus there is a SKILL.md file you can have your GitHub Copilot agent use to help you author a rule! 

Try it and tell us what you think

The Azure Policy Linter is open source under the MIT License. Clone it, build it, and run it against your own definitions:

We’re not accepting pull requests just yet, but we would love your feedback, bug reports, gotchas we haven’t codified, and rule ideas. Please open an issue and help us make Azure Policy authoring safer and simpler for everyone.

Updated Aug 25, 2026
Version 1.0