orchestration/scripts/New-PolicyRemediation.ps1 (138 lines of code) (raw):
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
<#
.SYNOPSIS
The powershell script creates policy remediations.
#>
param (
$parAttendedLogin = $true
)
. ".\Invoke-Helper.ps1"
#variables
$varPolicyRemediationRequiredParams = @('parDeploymentPrefix', 'parDeploymentLocation')
$varPolicyRemediationBicepFilePath = '..\policyRemediation\policyRemediation.bicep'
<#
.Description
The function call is to create policy remediations for the policies that needs to be remediated
Parameters:
parPolicyExemptionParametersFilePath -> path to the parameter file containing required parameters to create policy remediations
parParameters -> hash table containing parameter name and value
#>
function Invoke-PolicyRemediation {
param($parPolicyRemediationParametersFilePath, $parParameters)
if (!$parParameters) {
$parParameters = Read-ParametersValue $parPolicyRemediationParametersFilePath
Confirm-Parameters $varPolicyRemediationRequiredParams
}
$parDeploymentPrefix = $parParameters.parDeploymentPrefix.value
$parDeploymentSuffix = $parParameters.parDeploymentSuffix.value
$varManagementGroupId = "$parDeploymentPrefix$parDeploymentSuffix"
$varPolicyStateList = Get-AzPolicyState -ManagementGroupName $varManagementGroupId -Filter "(PolicyDefinitionAction eq 'deployifnotexists' or PolicyDefinitionAction eq 'modify') and ComplianceState eq 'NonCompliant'"
if ( $null -ne $varPolicyStateList) {
$varPolicyCount = $varPolicyStateList.Count
Write-Information ">>> Starting policy remediation deployment" -InformationAction Continue
$varPolicyCounter = 1
foreach ($varPolicy in $varPolicyStateList) {
Write-Information "Remediating policy $varPolicyCounter out of $varPolicyCount policies." -InformationAction Continue
$varPolicyCounter++
New-Remediation $varPolicy
}
}
else {
Write-Information "No policies found for remediation." -InformationAction Continue
}
}
<#
.Description
Deploys Policy Remediation
#>
function New-Remediation {
param($parPolicy)
$varPolicySetDefinitionName = $parPolicy.policySetDefinitionName
$varGuid = New-Guid
$varDeploymentName = ("$varGuid" + $varPolicySetDefinitionName)
$varDeploymentName = $varDeploymentName.Length -ge 64 ? $varDeploymentName.Substring(0, 64) : $varDeploymentName
$parDeploymentPrefix = $parParameters.parDeploymentPrefix.value
$parDeploymentSuffix = $parParameters.parDeploymentSuffix.value
$varManagementGroupId = "$parDeploymentPrefix$parDeploymentSuffix"
$parDeploymentLocation = $parParameters.parDeploymentLocation.value
$parPolicyAssignmentScope = $parPolicy.policyAssignmentScope
$varPattern = "$([regex]::escape($parDeploymentPrefix))(.*)"
$varRegExResult = $parPolicyAssignmentScope | Select-String -Pattern $varPattern
$parManagementGroupScope = $varRegExResult.Matches[0].Value
$parParams = @{
parDeploymentPrefix = $parDeploymentPrefix
parDeploymentSuffix = $parDeploymentSuffix
parPolicyRemediationName = "rem-" + $varDeploymentName
parPolicyAssignmentId = $parPolicy.policyAssignmentId
parPolicyDefinitionReferenceId = $parPolicy.policyDefinitionReferenceId
parManagementGroupScope = $parManagementGroupScope
}
$parInvokePolicyRemediationSync = $parParameters.parInvokePolicyRemediationSync.value
$varRetry = $true
while ($varRetry -and $varLoopCounter -lt $varMaxRetryAttemptTransientErrorRetry) {
$modDeployPolicyRemediation = $null
try {
if ($parInvokePolicyRemediationSync) {
$varJob = $modDeployPolicyRemediation = New-AzManagementGroupDeployment `
-Name $varDeploymentName `
-Location $parDeploymentLocation `
-TemplateFile $varPolicyRemediationBicepFilePath `
-ManagementGroupId $varManagementGroupId `
-TemplateParameterObject $parParams `
-WarningAction Ignore `
-AsJob
$varJob | Wait-Job
if (!$modDeployPolicyRemediation) {
Write-Error "`n>>> Error occured in policy remediation" -ErrorAction Stop
}
if ($modDeployPolicyRemediation.ProvisioningState -eq "Failed") {
Write-Error "`n Error while executing policy remediation deployment" -ErrorAction Stop
}
Write-Information ">>> Policy remediation $($parParams.parPolicyRemediationName) completed." -InformationAction Continue
return
}
else {
$modDeployPolicyRemediation = New-AzManagementGroupDeployment `
-Name $varDeploymentName `
-Location $parDeploymentLocation `
-TemplateFile $varPolicyRemediationBicepFilePath `
-ManagementGroupId $varManagementGroupId `
-TemplateParameterObject $parParams `
-WarningAction Ignore `
-AsJob
Write-Information ">>> Policy remediation $($parParams.parPolicyRemediationName) scheduled." -InformationAction Continue
return
}
}
catch {
$varException = $_.Exception
$varErrorDetails = $_.ErrorDetails
$varTrace = $_.ScriptStackTrace
if (!$varRetry) {
Write-Error ">>> Validation error occurred during execution . Please try after addressing the error : $varException \n $varErrorDetails \n $varTrace" -ErrorAction Stop
}
if (!$modDeployPolicyRemediation) {
Write-Error ">>> Error occurred during execution . Please try after addressing the error : $varException \n $varErrorDetails \n $varTrace" -ErrorAction Stop
}
else {
$varDeploymentErrorCodes = Get-FailedDeploymentErrorCodes $varManagementGroupId $varDeploymentName $varManagementGroupDeployment
if ($null -eq $varDeploymentErrorCodes) {
$varRetry = $false
}
else {
$varLoopCounter++
$varRetry = Confirm-Retry $varDeploymentErrorCodes
if ($varRetry -and $varLoopCounter -lt $varMaxRetryAttemptTransientErrorRetry) {
Write-Information ">>> Retrying deployment after waiting for $varRetryWaitTimeTransientErrorRetry secs" -InformationAction Continue
Start-Sleep -Seconds $varRetryWaitTimeTransientErrorRetry
}
else {
$varRetry = $false
Write-Error ">>> Error occurred in policy remediation deployment. Please try after addressing the above error." -ErrorAction Stop
}
}
}
}
}
}