You dont have javascript enabled! Please enable it!

Duplicate Azure Policy Definition and Initiative

5 Min. Read

In this article, we will share with you how to duplicate the Azure Policy definition and initiative with PowerShell.

A common theme in cloud environments is enforcing organizational standards and adopting cloud governance since day one. And this is very important since it will give you the ability to define policies, processes, and procedures. These policies then dictate what can be done and verify that what does exist is correct. A service from Microsoft called Azure Policy is a great way to make that happen and take proactive action.

Introduction

Azure Policy is a service in Azure that you use to create, assign, and manage policies. These policies enforce different rules and effects on your resources, so those resources stay compliant with your corporate standards and service level agreements. Azure Policy meets this need by continuously evaluating your resources for non-compliance with assigned policies.

A while ago, I wrote an article that would help you to export Azure Policy (custom) definitions and then upload them to an Azure storage account as a backup. This comes in handy when working and updating many policies, so you can have a backup copy to revert back if needed, and this is also helpful for auditing purposes.

I was working recently on an interesting scenario where we need to duplicate existing (custom and built-in) policies (definition and initiative) so we can work with and customize them further as needed.

I  have developed a handy tool that will automate the entire process for you, so you can specify if the policy that you want to duplicate is a single policy or initiative (set of policies).

Prerequisites

To run this tool, you need to have the following:

1) An Azure subscription. If you don’t have an Azure subscription, you can create a free one here.

2) You need to have the appropriate permissions to create and manage Azure Policy. The Azure RBAC built-in roles that you can use are Resource Policy Contributor or Security Admin.

3) The Azure PowerShell (Az module) is installed locally on your machine. You can use the following PowerShell command to install and update the “Az module”.

# Make sure you have the latest version of PowerShellGet installed
Install-Module -Name PowerShellGet -Force

# Install and update to the latest Az PowerShell module
Install-Module -Name Az -AllowClobber -Force

Assuming you have all the prerequisites in place, run the following PowerShell tool.

Duplicate Azure Policy with PowerShell

Here is the PowerShell tool that will do the job for you.

<#
.Synopsis
A script used to duplicate Azure Policy Definitions and Initiatives.

.DESCRIPTION
A script used to duplicate an existing Azure Policy definition or initiative in your Azure Subscription(s).
Create a new policy definition or initiative with a new name based on existing scope (Subscription or Management Group).
The tool will work for both Custom and BuiltIn Policies.

.Notes
FileName  : Duplicate-AzPolicy
Created   : 03-March-2022
Updated   : 04-March-2022
Version   : 1.0
Author    : Charbel Nemnom
Twitter   : @CharbelNemnom
Blog      : https://charbelnemnom.com
Disclaimer: This script is provided "AS IS" with no warranties.
#>

Param(
    [parameter(Mandatory=$true, HelpMessage='Existing Azure Policy Name')]
    [ValidateNotNullOrEmpty()]
    [string]$PolicyName,

    [parameter(Mandatory=$true, HelpMessage='New Azure Policy Name')]
    [ValidateNotNullOrEmpty()]
    [string]$NewPolicyName,

    [parameter(Mandatory=$true, HelpMessage='New Policy Display Name')]
    [ValidateNotNullOrEmpty()]
    [string]$NewDisplayName,

    [ValidateSet("Policy", "Initiative")]
    [String]$Policy='Policy',

    [Parameter(Mandatory=$false, HelpMessage='Azure Subscription Name')]
    [String]$SubscriptionName
)

#! Login with Connect-AzAccount if NOT using Cloud Shell
#! Check Azure Connection
Try { Write-Verbose "Connecting to Azure Cloud..."
     Connect-AzAccount -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
}
Catch {
    Write-Warning "Cannot connect to Azure Cloud. Please check your credentials. Exiting!"
    Exit
}

If ($SubscriptionName) {
    #! Set Azure Subscription Context
    Try {
        Write-Verbose "Setting Azure Context - Subscription Name: $SubscriptionName..."
        $azSub = Get-AzSubscription -SubscriptionName $SubscriptionName
        Set-AzContext $azSub.id | Out-Null
    }
    Catch {
        Write-Warning "Cannot set Azure context. Please check your Azure subscription name. Exiting!"
        Exit
    }
}

switch ($Policy) {
    Initiative {
        # Get the initiative's properties using the name
        $Initiative = Get-AzPolicySetDefinition | Where-Object {$_.Properties.DisplayName -eq $PolicyName}
        If (!$Initiative) {
            Write-Warning "Cannot find existing Policy. Please check your Azure Policy Name. Exiting!"
            Exit
         }
        $PolicyType = $Initiative.Properties.PolicyType
        $Mgr = $Initiative.ResourceId.Contains("managementGroups")
        $Sub = $Initiative.ResourceId.Contains("subscriptions")
        If ($Mgr) {
            $mgrName = $Definition.ResourceId -split "managementGroups"
            $mgrName = $mgrName[1].Split('/')[+1]
        } elseif ($Sub) {
            $subName = $Definition.ResourceId -split "subscriptions"
            $subId = $subName[1].Split('/')[+1]
        }
        If ($PolicyType -eq "BuiltIn") {
            $Sub = (Get-AzContext).Subscription.Name
            $subId = (Get-AzContext).Subscription.ID
        }
    }
    Policy {
        # Get the definition's properties using the name
        $Definition = Get-AzPolicyDefinition | Where-Object {$_.Properties.DisplayName -eq $PolicyName}
        If (!$Definition) {
            Write-Warning "Cannot find existing Policy. Please check your Azure Policy Name. Exiting!"
            Exit
         }
        $PolicyType = $Definition.Properties.PolicyType
        $Mgr = $Definition.ResourceId.Contains("managementGroups")
        $Sub = $Definition.ResourceId.Contains("subscriptions")
        If ($Mgr) {
            $mgrName = $Definition.ResourceId -split "managementGroups"
            $mgrName = $mgrName[1].Split('/')[+1]
        } elseif ($Sub) {
            $subName = $Definition.ResourceId -split "subscriptions"
            $subId = $subName[1].Split('/')[+1]
        }
        If ($PolicyType -eq "BuiltIn") {
            $Sub = (Get-AzContext).Subscription.Name
            $subId = (Get-AzContext).Subscription.ID
        }
    }
}

If (!$Mgr -and !$Sub -and !$PolicyType) {
    Write-Warning "Cannot find existing Policy. Please check your Azure Policy Name. Exiting!"
    Exit
 }

If ($Mgr) {
    switch ($Policy) {
        Initiative {
        # Duplicate Custom or BuiltIn Policy Initiative
        New-AzPolicySetDefinition `
            -Name $NewPolicyName `
            -DisplayName $NewDisplayName `
            -Description $Initiative.Properties.Description `
            -PolicyDefinition $([System.Text.RegularExpressions.Regex]::Unescape($($Initiative.Properties.PolicyDefinitions | ConvertTo-Json -Depth 100))) `
            -Metadata $($Initiative.Properties.Metadata | ConvertTo-Json  -Depth 100)  `
            -Parameter $($Initiative.Properties.Parameters | ConvertTo-Json  -Depth 100)  `
            -ManagementGroupName $mgrName `
            -GroupDefinition $($Initiative.Properties.PolicyDefinitionGroups | ConvertTo-Json  -Depth 100)
    }
        Policy {
        # Duplicate Custom or BuiltIn Policy Definition
        New-AzPolicyDefinition `
            -Name $NewPolicyName `
            -DisplayName $NewDisplayName `
            -Description $Definition.Properties.Description `
            -Policy $($Definition.Properties.PolicyRule | ConvertTo-Json -Depth 100)  `
            -Metadata $($Definition.Properties.Metadata | ConvertTo-Json  -Depth 100)  `
            -Parameter $($Definition.Properties.Parameters | ConvertTo-Json  -Depth 100)  `
            -ManagementGroupName $mgrName
        }
    }
}

If ($Sub -and $PolicyType) {
    switch ($Policy) {
        Initiative {
        # Duplicate Custom or BuiltIn Policy Initiative
        New-AzPolicySetDefinition `
            -Name $NewPolicyName `
            -DisplayName $NewDisplayName `
            -Description $Initiative.Properties.Description `
            -PolicyDefinition $([System.Text.RegularExpressions.Regex]::Unescape($($Initiative.Properties.PolicyDefinitions | ConvertTo-Json -Depth 100))) `
            -Metadata $($Initiative.Properties.Metadata | ConvertTo-Json  -Depth 100)  `
            -Parameter $($Initiative.Properties.Parameters | ConvertTo-Json  -Depth 100)  `
            -SubscriptionId $subId `
            -GroupDefinition $($Initiative.Properties.PolicyDefinitionGroups | ConvertTo-Json  -Depth 100)
    }
        Policy {
        # Duplicate Custom or BuiltIn Policy Definition
        New-AzPolicyDefinition `
            -Name $NewPolicyName `
            -DisplayName $NewDisplayName `
            -Description $Definition.Properties.Description `
            -Policy $($Definition.Properties.PolicyRule | ConvertTo-Json -Depth 100) `
            -Metadata $($Definition.Properties.Metadata | ConvertTo-Json  -Depth 100)  `
            -Parameter $($Definition.Properties.Parameters | ConvertTo-Json  -Depth 100)  `
            -SubscriptionId $subId
        }
    }
}

This tool will perform the following steps:

  • You specify the existing policy name, this could be a policy initiative or definition.
  • You set a new policy name and a new policy display name.
  • Then you specify if the existing policy that you want to duplicate is a single policy definition or initiative definition (set). By default, the tool will target a single policy, you need the set the -Policy switch to ‘Initiative‘.
  • Optionally, you can specify the subscription name if the existing policy (definition location scope) is set at the subscription level. By default, the tool will target all the policies at the management group level.
  • Finally, it will create a new policy definition or initiative with a new name based on the existing scope whether it’s subscription or management group.
  • The tool will work for both Custom and BuiltIn Policies. If the Policy Type is ‘BuiltIn‘ and not ‘Custom‘, it will create the new policy and set the definition location based on the current session (subscription) context.

Run the tool

To run the tool, you could use the Azure Cloud Shell at (https://shell.azure.com), the Azure Cloud Shell Connector in Windows Terminal, or the Azure PowerShell module installed locally on your machine.

Here is how to run this tool in action.

# Example
.\Duplicate-AzPolicy.ps1 -PolicyName "UK OFFICIAL and UK NHS" -NewPolicyName "UK OFFICIAL and UK NHS-Custom1" -NewDisplayName "UK OFFICIAL and UK NHS-Custom1" -Policy Initiative -Verbose
Duplicate Azure Policy
Duplicate Azure Policy

Finally, switch to the Azure portal (Policy Menu Blade), you can see that the new policy (definition and initiative) with a new name is created as shown in the figure below.

New Policy Initiative Definition
New Policy Initiative Definition

Please note that you can accomplish the same thing using Azure CLI, however, I prefer to use Azure PowerShell.

Happy Azure Policy Duplication!

Summary

In this article, we showed you how to duplicate the Azure Policy definition and initiative with PowerShell.

This is version 1.0 of this tool, do you want additional features? Please feel free to leave a comment below.

> Learn more about enabling HTTPS on Azure App Services with Azure Policy, check the following step-by-step guide.

> Learn more about enforcing TLS 1.2 on Web Apps with Azure Policy, check the following step-by-step guide.

> Learn more about auditing publicly accessible Azure App Services with Azure Policy, check the following step-by-step guide.

> Learn more about auditing subnets that do not have Network Security Group (NSG) associated, check the following step-by-step guide.

> Learn more about enabling diagnostic settings for storage accounts to Event Hub, check the following step-by-step guide.

> Learn more about Azure Policy, check the official documentation from Microsoft.

That’s it there you have it!

__
Thank you for reading my blog.

If you have any questions or feedback, please leave a comment.

-Charbel Nemnom-

Related Posts

Previous

Advanced Azure AD Hunting with Microsoft Sentinel

AZ-720 Study Guide: Troubleshooting Microsoft Azure Connectivity

Next

Let me know what you think, or ask a question...

error: Alert: The content of this website is copyrighted from being plagiarized! You can copy from the 'Code Blocks' in 'Black' by selecting the Code. Thank You!