Skip to content

Commit

Permalink
Bug Fixes (#587)
Browse files Browse the repository at this point in the history
  • Loading branch information
techlake authored Apr 25, 2024
1 parent 8134a9a commit 5c6f5e3
Show file tree
Hide file tree
Showing 35 changed files with 222 additions and 206 deletions.
4 changes: 2 additions & 2 deletions Docs/operational-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The scripts are detailed in the [reference page](operational-scripts-reference.m

## Batch Creation of Remediation Tasks

The script `Create-AzRemediationTasks` creates remediation tasks for all non-compliant resources for EPAC environments in the `global-settings.jsonc` file.
The script `New-AzRemediationTasks` creates remediation tasks for all non-compliant resources for EPAC environments in the `global-settings.jsonc` file.

This script executes all remediation tasks in a Policy as Code environment specified with parameter `PacEnvironmentSelector`. The script will interactively prompt for the value if the parameter is not supplied. The script will recurse the Management Group structure and subscriptions from the defined starting point.

Expand Down Expand Up @@ -34,7 +34,7 @@ The Hydration Kit is a set of scripts that can be used to deploy an EPAC environ

## CI/CD Helpers

The scripts `Create-AzureDevOpsBug` and `Create-GitHubIssue` create a Bug or Issue when there are one or multiple failed Remediation Tasks.
The scripts `New-AzureDevOpsBug` and `New-GitHubIssue` create a Bug or Issue when there are one or multiple failed Remediation Tasks.

## Non-compliance Reports

Expand Down
11 changes: 11 additions & 0 deletions Module/EnterprisePolicyAsCode/EnterprisePolicyAsCode.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@

# Aliases to export from this module
AliasesToExport = ''

RequiredModules = @(
@{
ModuleName = 'Az.Accounts'
ModuleVersion = '2.9.1'
},
@{
ModuleName = 'Az.ResourceGraph'
ModuleVersion = '0.13.0'
}
)

# List of all files packaged with this module
FileList = @()
Expand Down
2 changes: 1 addition & 1 deletion Module/EnterprisePolicyAsCode/EnterprisePolicyAsCode.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Recurse -

foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Recurse -File -Filter "*.ps1")) {
. Import-ModuleFile -Path $function.FullName
Export-ModuleMember $function.BaseName -Verbose
Export-ModuleMember $function.BaseName
}
#endregion Load functions

Expand Down
2 changes: 1 addition & 1 deletion Scripts/Helpers/Add-HelperScripts.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@
. "$PSScriptRoot/Get-AzPolicyResources.ps1"
. "$PSScriptRoot/Get-AzPolicyResourcesDetails.ps1"
. "$PSScriptRoot/Get-CalculatedPolicyAssignmentsAndReferenceIds.ps1"
. "$PSScriptRoot/Get-ClonedObject.ps1"
. "$PSScriptRoot/Get-CustomMetadata.ps1"
. "$PSScriptRoot/Get-DeepCloneAsOrderedHashtable.ps1"
. "$PSScriptRoot/Get-DefinitionsFullPath.ps1"
. "$PSScriptRoot/Get-DeploymentPlan.ps1"
. "$PSScriptRoot/Get-GlobalSettings.ps1"
Expand Down
4 changes: 2 additions & 2 deletions Scripts/Helpers/Build-AssignmentDefinitionAtLeaf.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ function Build-AssignmentDefinitionAtLeaf {
continue
}
$enforcementMode = $AssignmentDefinition.enforcementMode
$metadata = Get-ClonedObject $AssignmentDefinition.metadata -AsHashTable
$metadata = Get-DeepCloneAsOrderedHashtable $AssignmentDefinition.metadata
if ($metadata.ContainsKey("pacOwnerId")) {
Write-Error " Leaf Node $($nodeName): metadata.pacOwnerId ($($metadata.pacOwnerId)) may not be set explicitly; it is reserved for EPAC usage."
$hasErrors = $true
Expand Down Expand Up @@ -567,7 +567,7 @@ function Build-AssignmentDefinitionAtLeaf {
foreach ($scopeEntry in $scopeCollection) {

# Clone hashtable
[hashtable] $scopedAssignment = Get-ClonedObject $baseAssignment -AsHashTable
[hashtable] $scopedAssignment = Get-DeepCloneAsOrderedHashtable $baseAssignment

# Add scope and if defined notScopes()
$scope = $scopeEntry.scope
Expand Down
9 changes: 5 additions & 4 deletions Scripts/Helpers/Build-AssignmentDefinitionNode.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function Build-AssignmentDefinitionNode {
)

# Each tree branch needs a private copy
$definition = Get-ClonedObject -InputObject $AssignmentDefinition
$definition = Get-DeepCloneAsOrderedHashtable -InputObject $AssignmentDefinition
$pacSelector = $PacEnvironment.pacSelector

#region nodeName (required)
Expand Down Expand Up @@ -157,7 +157,8 @@ function Build-AssignmentDefinitionNode {
if ($DefinitionNode.metadata) {
# merge metadata
$metadata = $definition.metadata
$merge = Get-ClonedObject $DefinitionNode.metadata -AsHashTable
$merge = Get-DeepCloneAsOrderedHashtable $DefinitionNode.metadata

foreach ($key in $merge.Keys) {
$metadata[$key] = $merge.$key
}
Expand All @@ -170,7 +171,7 @@ function Build-AssignmentDefinitionNode {
$addedParameters = $DefinitionNode.parameters
foreach ($parameterName in $addedParameters.Keys) {
$rawParameterValue = $addedParameters.$parameterName
$parameterValue = Get-ClonedObject $rawParameterValue -AsHashTable
$parameterValue = Get-DeepCloneAsOrderedHashtable $rawParameterValue
$allParameters[$parameterName] = $parameterValue
}
}
Expand All @@ -189,7 +190,7 @@ function Build-AssignmentDefinitionNode {
$fullName = $ParameterFilesCsv.$parameterFileName
$content = Get-Content -Path $fullName -Raw -ErrorAction Stop
$xlsArray = @() + ($content | ConvertFrom-Csv -ErrorAction Stop)
$csvParameterArray = Get-ClonedObject $xlsArray -AsHashTable
$csvParameterArray = Get-DeepCloneAsOrderedHashtable $xlsArray
$definition.parameterFileName = $parameterFileName
$definition.csvParameterArray = $csvParameterArray
$definition.csvRowsValidated = $false
Expand Down
8 changes: 6 additions & 2 deletions Scripts/Helpers/Build-AssignmentPlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function Build-AssignmentPlan {
# Cache role assognments and definitions
$deployedPolicyAssignments = $deployedPolicyResources.policyassignments.managed
$deployedRoleAssignmentsByPrincipalId = $DeployedPolicyResources.roleAssignmentsByPrincipalId
$deleteCandidates = Get-ClonedObject $deployedPolicyAssignments -AsHashTable -AsShallowClone
$deleteCandidates = $deployedPolicyAssignments.Clone()
$roleDefinitions = $DeployedPolicyResources.roleDefinitions

# Process each assignment file
Expand All @@ -50,8 +50,9 @@ function Build-AssignmentPlan {
}

# Write-Information ""
$assignmentObject = $null
try {
$assignmentObject = $Json | ConvertFrom-Json -AsHashtable
$assignmentObject = $Json | ConvertFrom-Json -Depth 100 -AsHashtable
}
catch {
Write-Error "Assignment JSON file '$($assignmentFile.FullName)' is not valid." -ErrorAction Stop
Expand Down Expand Up @@ -189,6 +190,9 @@ function Build-AssignmentPlan {
}
$changesStrings += ($identityStatus.changedIdentityStrings)
}
elseif ($identityStatus.requiresRoleChanges) {
$changesStrings += ($identityStatus.changedIdentityStrings)
}

if (!$displayNameMatches) {
$changesStrings += "displayName"
Expand Down
39 changes: 22 additions & 17 deletions Scripts/Helpers/Build-ExemptionsPlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ function Build-ExemptionsPlan {
param (
[string] $ExemptionsRootFolder,
[string] $ExemptionsAreNotManagedMessage,
[hashtable] $PacEnvironment,
$PacEnvironment,
$ScopeTable,
[hashtable] $AllDefinitions,
[hashtable] $AllAssignments,
[hashtable] $CombinedPolicyDetails,
[hashtable] $Assignments,
[hashtable] $DeployedExemptions,
[hashtable] $Exemptions
$AllDefinitions,
$AllAssignments,
$CombinedPolicyDetails,
$Assignments,
$DeployedExemptions,
$Exemptions
)

Write-Information "==================================================================================================="
Expand All @@ -25,7 +25,7 @@ function Build-ExemptionsPlan {

$uniqueIds = @{}
$deployedManagedExemptions = $DeployedExemptions.managed
$deleteCandidates = Get-ClonedObject $deployedManagedExemptions -AsHashTable -AsShallowClone
$deleteCandidates = $deployedManagedExemptions.Clone()
$replacedAssignments = $Assignments.replace
$numberOfFilesWithErrors = 0
$desiredState = $PacEnvironment.desiredState
Expand Down Expand Up @@ -65,7 +65,7 @@ function Build-ExemptionsPlan {
Write-Information "Processing file '$($fullName)'"
Write-Information "---------------------------------------------------------------------------------------------------"
$errorInfo = New-ErrorInfo -FileName $fullName
$exemptionsArray = @()
$exemptionsArray = [System.Collections.ArrayList]::new()
$isCsvFile = $false
if ($extension -eq ".json" -or $extension -eq ".jsonc") {
$content = Get-Content -Path $fullName -Raw -ErrorAction Stop
Expand All @@ -79,16 +79,21 @@ function Build-ExemptionsPlan {
if ($null -ne $jsonObj) {
$jsonExemptions = $jsonObj.exemptions
if ($null -ne $jsonExemptions -and $jsonExemptions.Count -gt 0) {
$exemptionsArray += $jsonExemptions
$null = $exemptionsArray.AddRange($jsonExemptions)
}
}
}
elseif ($extension -eq ".csv") {
$isCsvFile = $true
$content = Get-Content -Path $fullName -Raw -ErrorAction Stop
$xlsExemptions = ($content | ConvertFrom-Csv -ErrorAction Stop)
if ($xlsExemptions.Count -gt 0) {
$exemptionsArray += $xlsExemptions
if ($null -ne $xlsExemptions) {
if ($xlsExemptions -isnot [array]) {
$xlsExemptions = @($xlsExemptions)
}
if ($xlsExemptions.Count -gt 0) {
$null = $exemptionsArray.AddRange($xlsExemptions)
}
}
}
#endregion read each file
Expand Down Expand Up @@ -178,7 +183,7 @@ function Build-ExemptionsPlan {
$step1 = $policyDefinitionReferenceIds
if (-not [string]::IsNullOrWhiteSpace($step1)) {
$step2 = $step1.Trim()
$step3 = $step2 -split ":"
$step3 = $step2 -split "&"
foreach ($item in $step3) {
$step4 = $item.Trim()
if ($step4.Length -gt 0) {
Expand Down Expand Up @@ -505,6 +510,7 @@ function Build-ExemptionsPlan {
$splits = $currentScope -split "/"
$trimmedScope = $splits[0..4] -join "/"
if ($validateScope) {
$thisResourceIdExists = $false
if ($resourceIdsExist.ContainsKey($currentScope)) {
$thisResourceIdExists = $resourceIdsExist.$currentScope
}
Expand Down Expand Up @@ -533,7 +539,7 @@ function Build-ExemptionsPlan {
$uniqueAssignmentNames = @{}
if ($null -ne $policyAssignmentId -and !$validateScope) {
$calculatedPolicyAssignment = $calculatedPolicyAssignments[0]
$clonedCalculatedPolicyAssignment = Get-ClonedObject $calculatedPolicyAssignment -AsShallowClone
$clonedCalculatedPolicyAssignment = $calculatedPolicyAssignment.Clone()
$null = $filteredPolicyAssignments.Add($clonedCalculatedPolicyAssignment)
}
else {
Expand Down Expand Up @@ -566,7 +572,7 @@ function Build-ExemptionsPlan {
$listOfAssignmentsWithSameName = [System.Collections.ArrayList]::new()
$null = $uniqueAssignmentNames.Add($calculatedPolicyAssignment.name, $listOfAssignmentsWithSameName)
}
$clonedCalculatedPolicyAssignment = Get-ClonedObject $calculatedPolicyAssignment -AsShallowClone
$clonedCalculatedPolicyAssignment = $calculatedPolicyAssignment.Clone()
$null = $listOfAssignmentsWithSameName.Add($clonedCalculatedPolicyAssignment)
$null = $filteredPolicyAssignments.Add($clonedCalculatedPolicyAssignment)
}
Expand Down Expand Up @@ -719,8 +725,7 @@ function Build-ExemptionsPlan {
ordinalString = $ordinalString
}
$epacMetadata += $epacMetadataDefinitionSpecification
$clonedMetadata = $null
$clonedMetadata = Get-ClonedObject $metadata -AsShallowClone
$clonedMetadata = Get-DeepCloneAsOrderedHashtable $metadata
$clonedMetadata.pacOwnerId = $PacEnvironment.pacOwnerId
$clonedMetadata.epacMetadata = $epacMetadata
if (!$clonedMetadata.ContainsKey("deployedBy")) {
Expand Down
25 changes: 13 additions & 12 deletions Scripts/Helpers/Build-PolicyPlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function Build-PolicyPlan {
}

$managedDefinitions = $DeployedDefinitions.managed
$deleteCandidates = Get-ClonedObject $managedDefinitions -AsHashTable -AsShallowClone
$deleteCandidates = $managedDefinitions.Clone()
$deploymentRootScope = $PacEnvironment.deploymentRootScope
$duplicateDefinitionTracking = @{}
$definitionsNew = $Definitions.new
Expand All @@ -39,8 +39,9 @@ function Build-PolicyPlan {

# Write-Information "Processing $($definitionFilesSet.Length) Policy files in this parallel execution."
$Json = Get-Content -Path $file.FullName -Raw -ErrorAction Stop
$definitionObject = $null
try {
$definitionObject = $Json | ConvertFrom-Json
$definitionObject = ConvertFrom-Json $Json -Depth 100
}
catch {
Write-Error "Assignment JSON file '$($file.FullName)' is not valid." -ErrorAction Stop
Expand All @@ -52,12 +53,12 @@ function Build-PolicyPlan {
$id = "$deploymentRootScope/providers/Microsoft.Authorization/policyDefinitions/$name"
$displayName = $definitionProperties.displayName
$description = $definitionProperties.description
$metadata = Get-ClonedObject $definitionProperties.metadata -AsHashTable
$metadata = Get-DeepCloneAsOrderedHashtable $definitionProperties.metadata
# $version = $definitionProperties.version
$mode = $definitionProperties.mode
$parameters = $definitionProperties.parameters
$policyRule = $definitionProperties.policyRule
if ($metadata) {
if ($null -ne $metadata) {
$metadata.pacOwnerId = $thisPacOwnerId
}
else {
Expand Down Expand Up @@ -125,25 +126,25 @@ function Build-PolicyPlan {
if ($managedDefinitions.ContainsKey($id)) {
# Update and replace scenarios
$deployedDefinition = $managedDefinitions[$id]
$deployedDefinition = Get-PolicyResourceProperties -PolicyResource $deployedDefinition
$deployedDefinitionProperties = Get-PolicyResourceProperties -PolicyResource $deployedDefinition

# Remove defined Policy entry from deleted hashtable (the hashtable originally contains all custom Policy in the scope)
$null = $deleteCandidates.Remove($id)

# Check if Policy in Azure is the same as in the JSON file
$displayNameMatches = $deployedDefinition.displayName -eq $displayName
$descriptionMatches = $deployedDefinition.description -eq $description
$modeMatches = $deployedDefinition.mode -eq $definition.Mode
$displayNameMatches = $deployedDefinitionProperties.displayName -eq $displayName
$descriptionMatches = $deployedDefinitionProperties.description -eq $description
$modeMatches = $deployedDefinitionProperties.mode -eq $definition.Mode
$metadataMatches, $changePacOwnerId = Confirm-MetadataMatches `
-ExistingMetadataObj $deployedDefinition.metadata `
-ExistingMetadataObj $deployedDefinitionProperties.metadata `
-DefinedMetadataObj $metadata
# $versionMatches = $version -eq $deployedDefinition.version
# $versionMatches = $version -eq $deployedDefinitionProperties.version
$versionMatches = $true
$parametersMatch, $incompatible = Confirm-ParametersDefinitionMatch `
-ExistingParametersObj $deployedDefinition.parameters `
-ExistingParametersObj $deployedDefinitionProperties.parameters `
-DefinedParametersObj $parameters
$policyRuleMatches = Confirm-ObjectValueEqualityDeep `
$deployedDefinition.policyRule `
$deployedDefinitionProperties.policyRule `
$policyRule

# Update Policy in Azure if necessary
Expand Down
15 changes: 11 additions & 4 deletions Scripts/Helpers/Build-PolicySetPlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function Build-PolicySetPlan {
}

$managedDefinitions = $DeployedDefinitions.managed
$deleteCandidates = Get-ClonedObject $managedDefinitions -AsHashTable -AsShallowClone
$deleteCandidates = $managedDefinitions.Clone()
$deploymentRootScope = $PacEnvironment.deploymentRootScope
$policyDefinitionsScopes = $PacEnvironment.policyDefinitionsScopes
$duplicateDefinitionTracking = @{}
Expand All @@ -35,6 +35,7 @@ function Build-PolicySetPlan {
foreach ($file in $definitionFiles) {
$Json = Get-Content -Path $file.FullName -Raw -ErrorAction Stop

$definitionObject = $null
try {
$definitionObject = $Json | ConvertFrom-Json -Depth 100
}
Expand All @@ -47,7 +48,7 @@ function Build-PolicySetPlan {
$id = "$deploymentRootScope/providers/Microsoft.Authorization/policySetDefinitions/$name"
$displayName = $definitionProperties.displayName
$description = $definitionProperties.description
$metadata = Get-ClonedObject $definitionProperties.metadata -AsHashTable
$metadata = Get-DeepCloneAsOrderedHashtable $definitionProperties.metadata
# $version = $definitionProperties.version
$parameters = $definitionProperties.parameters
$policyDefinitions = $definitionProperties.policyDefinitions
Expand Down Expand Up @@ -79,8 +80,14 @@ function Build-PolicySetPlan {
if ($null -eq $displayName) {
Write-Error "Policy Set '$name' from file '$($file.Name)' requires a displayName" -ErrorAction Stop
}
if ($null -eq $policyDefinitions -or $policyDefinitions.Count -eq 0) {
Write-Error "Policy Set '$displayName' from file '$($file.Name)' requires a policyDefinitions array with at least one entry" -ErrorAction Stop
if ($null -eq $policyDefinitions) {
Write-Error "Policy Set '$displayName' from file '$($file.Name)' requires a policyDefinitions entry; it is null. Did you misspell policyDefinitions (it is case sensitive)?" -ErrorAction Stop
}
elseif ($policyDefinitions -isnot [System.Collections.IList]) {
Write-Error "Policy Set '$displayName' from file '$($file.Name)' requires a policyDefinitions array; it is not an array." -ErrorAction Stop
}
elseif ($policyDefinitions.Count -eq 0) {
Write-Error "Policy Set '$displayName' from file '$($file.Name)' requires a policyDefinitions array with at least one entry; it has zero entries." -ErrorAction Stop
}
if ($duplicateDefinitionTracking.ContainsKey($id)) {
Write-Error "Duplicate Policy Set with name '$($name)' in '$($duplicateDefinitionTracking[$id])' and '$($file.FullName)'" -ErrorAction Stop
Expand Down
2 changes: 1 addition & 1 deletion Scripts/Helpers/Confirm-ActiveAzExemptions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function Confirm-ActiveAzExemptions {
$metadata = $null
}

$exemptionObj = [pscustomobject][ordered]@{
$exemptionObj = [ordered]@{
name = $name
displayName = $exemption.displayName
description = $exemption.description
Expand Down
Loading

0 comments on commit 5c6f5e3

Please sign in to comment.