Creating a Policy with PowerShell

An easy way to create new Policies in Azure is to use the Portal and duplicate an existing policy. However, when working with Infrastructure as Code, using the manual process is not ideal as the new policy won’t be part of the code. An option would be to export the existing policy and update the json which is then passed to the PowerShell. This is good, except what if the base policy is updated before the next environment it will be applied.

For this article, a new policy is created that will check a tag on all storage accounts.

Step 1: Getting the existing policy

Get-AzPolicyDefinition | `
    Where-Object {$_.Properties.metadata.category -eq "Tags"} | `
    Select-Object { $_.Properties.DisplayName }
$Policy = Get-AzPolicyDefinition | Where-Object { $_.Properties.DisplayName -eq 'Add or replace a tag on resources'}

Step 2: Get the Policy details printed to screen

Write-Host -ForegroundColor Green "Policy IF"
$Policy.Properties.PolicyRule.if| ConvertTo-Json
Write-Host -ForegroundColor Green "Policy THEN"
$Policy.Properties.PolicyRule.then | ConvertTo-Json
Write-Host -ForegroundColor Green "Policy THEN-DETAILS"
$Policy.Properties.PolicyRule.then.details | ConvertTo-Json

Step 3: Copy the information into a JSON file that follows the Policy Rule definition and make modifications to include the check for a Storage Account. Save the file and create a variable pointing to the file location

$PolicyRuleFile = ".\storage_tag_enforcement.json"

Step 4: Copy the data from the retrieved policy that will remain the same

$PolicyMetadata = $Policy.Properties.Metadata | ConvertTo-Json
$PolicyParameters = $Policy.Properties.Parameters | ConvertTo-Json

Step 5: Create the policy

# Creating a new Custom Policy
$StorageTagPolicy = New-AzPolicyDefinition `
    -Name 'StorageTag' `
    -DisplayName "Tag on Storage Accounts" `
    -Policy $PolicyRuleFile `
    -Parameter $PolicyParameters `
    -Metadata $PolicyMetadata

Step 6: Apply the new policy on the main subscription. Changing the scope, it is possible to apply the new policy to any other subscription or resource group

# Assign at Subscription Level
$SubscriptionId = Get-AzSubscription | Select-Object -First 1 -ExpandProperty Id
$PolicyAssignment = New-AzPolicyAssignment `
    -Name 'StorageTag' `
    -PolicyDefinition $StorageTagPolicy `
    -Scope "/subscriptions/$($SubscriptionId)" `
    -AssignIdentity `
    -Location "West Europe" `
    -PolicyParameterObject @{
        'tagName' = 'label'
        'tagValue' = 'policy-applied'

In the Assignment policy a Managed Identity is assigned within the specified location. This is necessary only if remediation tasks are to be executed.

Step 7: Run a Remediation task

Start-AzPolicyRemediation -Name "Set tag on all storage accounts" -PolicyAssignmentId $PolicyAssignment.ResourceId

Step 8: Check that the remediation task executed and the returned report

The code for this example can be found at