Problem:
In Azure Policy, there are many built-in initiative definitions. To jumpstart your adoption of Azure and to apply guard rails to your cloud environment, you may want to use one of these built-in initiatives. However, you may want to customize an initiative to meet your organization’s requirements or needs. This PowerShell solution will allow you duplicate a built-in initiative so you can customize which policy definitions are included in the initative.
Solution:
- Download the script.ps1 file from my Github repo.
- Open PowerShell.
- Ensure the AZ module is installed:
Get-Module -ListAvailable
- Change your working directory to the folder where you downloaded the script.
- Connect to Azure:
Connect-AzAccount
- Set the context to target the appropriate subscription. For example:
Set-AzContext -Subscription 'Visual Studio Enterprise Subscription'
- Find the name of the built-in initiative to duplicate:
(Get-AzPolicySetDefinition).Properties.DisplayName | Sort-Object
- Call the script using all the parameters. For example:
.\script.ps1 -Initiative 'NIST SP 800-53 R4' -NewName 'NIST SP 800-53 R4 Custom' -NewDisplayName 'NIST SP 800-53 R4 Custom'
Explanation:
This solution was created before the option to duplicate an initiative existed in the portal. Below I will explain the different sections of the code:
- Param block
Param(
[parameter(Mandatory=$true)][string]$Initiative,
[parameter(Mandatory=$true)][string]$NewName,
[parameter(Mandatory=$true)][string]$NewDisplayName
)
The parameters listed below are used in calling the script:
- Initiative: input the name of the desired initiative. The allowed names of built-in initiatives will be in the output from step 7 in the Solution section.
- NewName: input the name of the new initiative that will be created.
- NewDisplayName: input the display name of the new initiative that will be created.
- Collect data
# Get subscription ID
$Id = (Get-AzContext).Subscription.Id
# Get the initiative's properties using the name
$Initiative = Get-AzPolicySetDefinition | Where-Object {$_.Properties.DisplayName -eq $Name}
- Id: this variable collects your subscription ID which will be used later to create the new initiative definition.
- Initiative: this variable collects all the details of the desired built-in initiative and used to build out the details of the new initiative.
- Create new initiative definition
# Create a custom initiative
New-AzPolicySetDefinition `
-Name $NewName `
-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 $Id `
-GroupDefinition $($Initiative.Properties.PolicyDefinitionGroups | ConvertTo-Json -Depth 100)
In this last chunk of code, the “New-AzPolicySetDefinition” cmdlet is used to duplicate a built-in definition. For the Policy Definition parameter, the Unescape method is used to escape single quotes that might exist in the JSON. In many of the parameter values, the ConverTo-Json cmdlet is used since the values are required to be in JSON format. Though the JSON depth is usually shallow in policy initiatives, I used 100 to prevent any issues in the conversion.
Hi
I ran the script but encountered the following errors:
Exception calling “Unescape” with “1” argument(s): “Value cannot be null.
Parameter name: str”
At C:\Users\XXXX\Documents\WindowsPowerShell\Scripts\scripts.ps1:18 char:76
+ … :Unescape($($Initiative.Properties.PolicyDefinitions | ConvertTo-Json …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentNullException
New-AzPolicySetDefinition : Cannot validate argument on parameter ‘Description’. The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again.
At C:\Users\XXXXX\Documents\WindowsPowerShell\Scripts\scripts.ps1:17 char:18
+ -Description $Initiative.Properties.Description `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [New-AzPolicySetDefinition], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzurePolicySetDefinitionCmdlet
LikeLike
Hi Jose, can you provide the values you used to duplicate an Azure Policy Definition? Which version of PowerShell are you using? Which version of the AZ module are you using? I wrote this blog entry over a year ago so I’m not sure if anything has changed with the referenced cmdlets but I’ll see if I can help you out.
LikeLike