output/20260723_081532/govviz/ALZ_20260723_081601/Enterprise-Scale/src/scripts/Invoke-AlzCustomPolicyCheckAgainstBuiltIn.ps1
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "", Justification = "Coloured output required in this script")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseProcessBlockForPipelineCommand", "", Justification = "Not required for this script")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseOutputTypeCorrectly", "", Justification = "Not required for this script")] [CmdletBinding()] Param ( [string] [parameter(ValueFromPipeline)][ValidateSet(';', ',')][string]$CsvDelimiter = ';', [string] $FileTimeStampFormat = 'yyyyMMdd_HHmmss', [object] $validEffects = @('append', 'audit', 'auditIfNotExists', 'deny', 'deployIfNotExists', 'modify', 'manual', 'disabled', 'EnforceRegoPolicy', 'enforceSetting') ) #region helper if ($CsvDelimiter -eq ';') { $CsvDelimiterOpposite = ',' } if ($CsvDelimiter -eq ',') { $CsvDelimiterOpposite = ';' } #endregion helper #region AzAPICall try { $azAPICallConf = initAzAPICall -DebugAzAPICall $True } catch { Write-Host "Install AzAPICall Powershell Module https://www.powershellgallery.com/packages/AzAPICall (aka.ms/AzAPICall)" -ForegroundColor DarkRed Write-Host "Command: Install-Module -Name AzAPICall" -ForegroundColor Yellow throw } #endregion AzAPICall #region get ALZ policies.json $ALZRetryMax = 5 $ALZRetryCount = 0 do { $ALZRetryCount++ $ALZPoliciesRaw = Invoke-WebRequest -uri "https://raw.githubusercontent.com/Azure/Enterprise-Scale/main/eslzArm/managementGroupTemplates/policyDefinitions/policies.json" if ($ALZPoliciesRaw.StatusCode -ne 200) { Write-Host "getALZPolicies: $($ALZPoliciesRaw.StatusCode -eq 200) - try again in $($ALZRetryCount * 2) seconds" start-sleep -seconds ($ALZRetryCount * 2) } } until($ALZPoliciesRaw.StatusCode -eq 200 -or $ALZRetryCount -gt $ALZRetryMax) if ($ALZRetryCount -gt 10 -and $ALZPoliciesRaw.StatusCode -ne 200) { Write-Host "ALZ Policies failed" throw } #endregion get ALZ policies.json $jsonALZPolicies = $ALZPoliciesRaw.Content -replace "\[\[", '[' | ConvertFrom-Json [regex]$extractVariableName = "(?<=\[variables\(')[^']+" $refsPolicyDefinitionsAll = $extractVariableName.Matches($jsonALZPolicies.variables.loadPolicyDefinitions.All).Value $refsPolicyDefinitions = $extractVariableName.Matches($jsonALZPolicies.variables.loadPolicyDefinitions.$($azapicallconf['checkContext'].Environment.Name)).Value $listPolicyDefinitions = $refsPolicyDefinitionsAll + $refsPolicyDefinitions $policyDefinitionsALZ = $listPolicyDefinitions.ForEach({ $jsonALZPolicies.variables.$_ }) if ($policyDefinitionsALZ.Count -eq 0) { throw "Found $($policyDefinitionsALZ.Count) ALZ Policy definitions for $($azapicallconf['checkContext'].Environment.Name)" } else { function getHash { [CmdletBinding()] param ( [Parameter(Mandatory)] [object] $object ) return [System.BitConverter]::ToString([System.Security.Cryptography.HashAlgorithm]::Create("sha256").ComputeHash([System.Text.Encoding]::UTF8.GetBytes($object))) } function detectEffect { [CmdletBinding()] Param ( [object] $policyDefinition, [object] $validEffects ) $arrayeffect = @() if (-not [string]::IsNullOrWhiteSpace($policyDefinition.properties.policyRule.then.effect)) { if ($policyDefinition.properties.policyRule.then.effect -in $validEffects) { $arrayeffect += "fixed: $($policyDefinition.properties.policyRule.then.effect)" return $arrayeffect } else { $Regex = [Regex]::new("(?<=\[parameters\(')(.*)(?='\)\])") $Match = $Regex.Match($policyDefinition.properties.policyRule.then.effect) if ($Match.Success) { if (-not [string]::IsNullOrWhiteSpace($policyDefinition.properties.parameters.($Match.Value))) { #defaultValue if (($policyDefinition.properties.parameters.($Match.Value) | Get-Member).name -contains 'defaultvalue') { if (-not [string]::IsNullOrWhiteSpace($policyDefinition.properties.parameters.($Match.Value).defaultValue)) { if ($policyDefinition.properties.parameters.($Match.Value).defaultValue -in $validEffects) { $arrayeffect += "default: $($policyDefinition.properties.parameters.($Match.Value).defaultValue)" } else { Write-Host "invalid defaultValue effect $($policyDefinition.properties.parameters.($Match.Value).defaultValue) - $($policyDefinition.name) ($($policyDefinition.properties.policyType))" } } else { Write-Host "defaultValue empty - $($policyDefinition.name) ($($policyDefinition.properties.policyType))" } } else { Write-Host "no defaultvalue - $($policyDefinition.name) ($($policyDefinition.properties.policyType))" } #allowedValues if (($policyDefinition.properties.parameters.($Match.Value) | Get-Member).name -contains 'allowedValues') { if (-not [string]::IsNullOrWhiteSpace($policyDefinition.properties.parameters.($Match.Value).allowedValues)) { if ($policyDefinition.properties.parameters.($Match.Value).allowedValues.Count -gt 0) { #Write-Host "allowedValues count $($policyDefinition.properties.parameters.($Match.Value).allowedValues) - $($policyDefinition.name) ($($policyDefinition.properties.policyType))" $arrayAllowed = @() foreach ($allowedValue in $policyDefinition.properties.parameters.($Match.Value).allowedValues) { $arrayAllowed += $allowedValue } $arrayeffect += "allowed: $(($arrayAllowed | sort-object) -join ', ')" } } else { Write-Host "allowedValues empty - $($policyDefinition.name) ($($policyDefinition.properties.policyType))" } } else { Write-Host "no allowedValues- $($policyDefinition.name) ($($policyDefinition.properties.policyType))" } } else { Write-Host "unexpected - $($policyDefinition.name) ($($policyDefinition.properties.policyType))" } return $arrayeffect } } } else { Write-Host "no then effect - $($policyDefinition.name) ($($policyDefinition.properties.policyType))" } } $currentTask = 'Getting BuiltIn Policy definitions' $uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/providers/Microsoft.Authorization/policyDefinitions?api-version=2021-06-01&`$filter=policyType eq 'BuiltIn'" $method = 'GET' $policyDefinitionsBuiltIn = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask Write-Host "Found $($policyDefinitionsALZ.Count) ALZ Policy definitions for $($azapicallconf['checkContext'].Environment.Name)" Write-Host "Found $($policyDefinitionsBuiltIn.Count) BuiltIn Policy definitions for $($azapicallconf['checkContext'].Environment.Name)" $htHashesBuiltIn = @{} foreach ($policyDefinitionBuiltIn in $policyDefinitionsBuiltIn) { $policyObject = $policyDefinitionBuiltIn $effectBuiltIn = detectEffect -policyDefinition $policyObject -validEffects $validEffects $htHashesBuiltIn.($policyObject.name) = @{} $htHashesBuiltIn.($policyObject.name).policy = $policyObject $htHashesBuiltIn.($policyObject.name).effectBuiltIn = $effectBuiltIn -join "$CsvDelimiterOpposite " $htHashesBuiltIn.($policyObject.name).policyRuleHash = getHash -object ($policyObject.properties.policyRule | ConvertTo-Json -depth 99) $htHashesBuiltIn.($policyObject.name).policyRuleIfHash = getHash -object ($policyObject.properties.policyRule.if | ConvertTo-Json -depth 99) $htHashesBuiltIn.($policyObject.name).policyRuleThenHash = getHash -object ($policyObject.properties.policyRule.then | ConvertTo-Json -depth 99) } $arrayResults = [System.Collections.ArrayList]@() foreach ($policyDefinitionALZ in $policyDefinitionsALZ) { $policyObject = $policyDefinitionALZ | ConvertFrom-Json $effectALZ = (detectEffect -policyDefinition $policyObject -validEffects $validEffects) -join "$CsvDelimiterOpposite " $policyRuleHash = getHash -object ($policyObject.properties.policyRule | ConvertTo-Json -depth 99) if ($htHashesBuiltIn.values.policyRuleHash -contains $policyRuleHash) { $ref = ($htHashesBuiltIn.values.where({ $_.policyRuleHash -eq $policyRuleHash }) | Select-Object effectBuiltIn, @{Label = 'name'; Expression = { $_.policy.Name } }, @{Label = 'displayName'; Expression = { $_.policy.properties.displayName } }) Write-Host "ALZ '$($policyObject.name)' policy-Rule matches a BuiltIn policy def: id:'$($ref.Name)' displayName: '$($ref.displayName)'" -ForegroundColor Magenta Write-Host " - AzA ALZ Link: https://www.azadvertizer.net/azpolicyadvertizer/$($policyObject.name).html" -ForegroundColor Magenta Write-Host " - AzA BuiltIn Link: https://www.azadvertizer.net/azpolicyadvertizer/$($ref.Name).html" -ForegroundColor Magenta $null = $arrayResults.Add([PSCustomObject]@{ ALZPolicy = $policyObject.name ALZPolicyDisplayName = $policyObject.properties.displayName ALZEffect = $effectALZ ALZPolicyLink = "https://www.azadvertizer.net/azpolicyadvertizer/$($policyObject.name).html" Match = 'policyRule' MatchCount = $ref.Count BuiltInEffect = $ref.effectBuiltIn BuiltinPolicy = $ref.Name BuiltinPolicyDisplayName = $ref.displayName BuiltinPolicyLink = "https://www.azadvertizer.net/azpolicyadvertizer/$($ref.Name).html" }) } $policyRuleIfHash = getHash -object ($policyObject.properties.policyRule.if | ConvertTo-Json -depth 99) if ($htHashesBuiltIn.values.policyRuleIfHash -contains $policyRuleIfHash) { $ref = ($htHashesBuiltIn.values.where({ $_.policyRuleIfHash -eq $policyRuleIfHash }) | Select-Object effectBuiltIn, @{Label = 'name'; Expression = { $_.policy.Name } }, @{Label = 'displayName'; Expression = { $_.policy.properties.displayName } }) Write-Host "ALZ '$($policyObject.name)' policy-Rule-If match in $($ref.count) Builtin Policy defs" foreach ($entry in $ref) { $null = $arrayResults.Add([PSCustomObject]@{ ALZPolicy = $policyObject.name ALZPolicyDisplayName = $policyObject.properties.displayName ALZEffect = $effectALZ ALZPolicyLink = "https://www.azadvertizer.net/azpolicyadvertizer/$($policyObject.name).html" Match = 'policyRuleIf' MatchCount = $ref.Count BuiltInEffect = $entry.effectBuiltIn BuiltinPolicy = $entry.Name BuiltinPolicyDisplayName = $entry.displayName BuiltinPolicyLink = "https://www.azadvertizer.net/azpolicyadvertizer/$($entry.Name).html" }) } } $policyRuleThenHash = getHash -object ($policyObject.properties.policyRule.then | ConvertTo-Json -depth 99) if ($htHashesBuiltIn.values.policyRuleThenHash -contains $policyRuleThenHash) { $ref = ($htHashesBuiltIn.values.where({ $_.policyRuleThenHash -eq $policyRuleThenHash }) | Select-Object effectBuiltIn, @{Label = 'name'; Expression = { $_.policy.Name } }, @{Label = 'displayName'; Expression = { $_.policy.properties.displayName } }) Write-Host "ALZ '$($policyObject.name)' policy-Rule-Then match in $($ref.count) Builtin Policy defs" foreach ($entry in $ref) { $null = $arrayResults.Add([PSCustomObject]@{ ALZPolicy = $policyObject.name ALZPolicyDisplayName = $policyObject.properties.displayName ALZEffect = $effectALZ ALZPolicyLink = "https://www.azadvertizer.net/azpolicyadvertizer/$($policyObject.name).html" Match = 'policyRuleThen' MatchCount = $ref.Count BuiltInEffect = $entry.effectBuiltIn BuiltinPolicy = $entry.Name BuiltinPolicyDisplayName = $entry.displayName BuiltinPolicyLink = "https://www.azadvertizer.net/azpolicyadvertizer/$($entry.Name).html" }) } } } $fileTimestamp = (Get-Date -Format $FileTimeStampFormat) $arrayResults | Export-Csv -delimiter $CsvDelimiter -path "alzvsbuiltin_$($fileTimestamp).csv" -Encoding utf8 -UseQuotes AsNeeded } |