Public/Get-AzPolicyBaseline.ps1
|
function Get-AzPolicyBaseline { <# .SYNOPSIS Retrieve Azure Policy baseline from ALZ and/or MCSB sources. .DESCRIPTION Downloads and parses Azure Landing Zones (ALZ) baseline from AzAdvertizer CSV, optionally combines with Microsoft Cloud Security Benchmark (MCSB) from Azure. Returns a consolidated baseline with deduplication and source tracking. .PARAMETER IncludeAlz Include Azure Landing Zones baseline policies. Default: $true .PARAMETER IncludeMcsb Include Microsoft Cloud Security Benchmark policies. Default: $true .PARAMETER CsvPath Path to local AzAdvertizer CSV file (optional). If not specified, will download from CsvUrl. .PARAMETER CsvUrl URL to download AzAdvertizer CSV (optional). Default: Uses predefined AzAdvertizer URL. .PARAMETER SelectedAlzInitiatives Filter specific ALZ initiatives by name pattern. Empty array = include all initiatives. Example: @("alzroot", "alz-Identity") .PARAMETER CacheMaxAgeHours Maximum age in hours for cached CSV file. Default: 24 hours .EXAMPLE # Get both ALZ and MCSB baselines $baseline = Get-AzPolicyBaseline -IncludeAlz -IncludeMcsb Write-Host "Total policies in baseline: $($baseline.Policies.Count)" Write-Host "ALZ policies: $(($baseline.Policies | Where-Object { $_.BaselineSources -like '*ALZ*' }).Count)" Write-Host "MCSB policies: $(($baseline.Policies | Where-Object { $_.BaselineSources -like '*MCSB*' }).Count)" .EXAMPLE # Get only ALZ baseline with specific initiatives $baseline = Get-AzPolicyBaseline -IncludeAlz -IncludeMcsb:$false ` -SelectedAlzInitiatives @("alzroot", "alz-Identity") .EXAMPLE # Use custom CSV path $baseline = Get-AzPolicyBaseline -IncludeAlz -CsvPath "C:\Data\policies.csv" .OUTPUTS PSCustomObject with properties: - Policies: Array of policy objects with properties: * PolicyDisplayName: Display name of the policy * PolicyDefinitionId: Full Azure resource ID * Version: Policy version (e.g., "1.0.0") * Effect: Default effect (Audit, Deny, etc.) * Category: Policy category * Type: "Policy" or "PolicySet" * BaselineSources: "ALZ", "MCSB", or "ALZ, MCSB" - Index: PSCustomObject with hashtable indexes: * ById: Policies indexed by PolicyDefinitionId * ByName: Policies indexed by exact PolicyDisplayName * ByNormName: Policies indexed by normalized name .NOTES Requires Az.Resources module for MCSB baseline retrieval. ALZ baseline is retrieved from AzAdvertizer CSV (no Az module required). #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [switch]$IncludeAlz = $true, [switch]$IncludeMcsb = $true, [string]$CsvPath, [string]$CsvUrl, [string[]]$SelectedAlzInitiatives = @(), [int]$CacheMaxAgeHours = 24 ) begin { Write-Debug "Get-AzPolicyBaseline: Starting baseline retrieval" Write-Debug " IncludeAlz: $IncludeAlz" Write-Debug " IncludeMcsb: $IncludeMcsb" if (-not $IncludeAlz -and -not $IncludeMcsb) { throw "At least one of -IncludeAlz or -IncludeMcsb must be specified" } } process { try { $alzBaseline = @() $mcsbBaseline = @() # Step 1: Get ALZ baseline if requested if ($IncludeAlz) { Write-Verbose "Retrieving ALZ baseline from AzAdvertizer..." # Download or load CSV if ($CsvPath -and (Test-Path $CsvPath)) { Write-Verbose " Using local CSV: $CsvPath" $polCsv = Import-CsvWithFallback -Path $CsvPath } else { # Use Get-AzAdvertizerCsv with caching $defaultUrl = "https://www.azadvertizer.net/azpolicyadvertizer-comma.csv" $url = if ($CsvUrl) { $CsvUrl } else { $defaultUrl } $cacheFolder = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) "AzurePolicyWatch\Cache" if (-not (Test-Path $cacheFolder)) { New-Item -Path $cacheFolder -ItemType Directory -Force | Out-Null } $cachePath = Join-Path $cacheFolder "azpolicyadvertizer-comma.csv" Write-Verbose " Downloading from: $url" $csvPath = Get-AzAdvertizerCsv -Url $url -CachePath $cachePath -MaxAgeHours $CacheMaxAgeHours $polCsv = Import-CsvWithFallback -Path $csvPath } if (-not $polCsv) { throw "Failed to retrieve AzAdvertizer CSV" } Write-Verbose " CSV loaded: $($polCsv.Count) total rows" # Detect ALZ initiatives $alzInitiatives = Get-AlzInitiatives -CsvData $polCsv Write-Verbose " ALZ initiatives found: $($alzInitiatives.Count)" # Import ALZ baseline $alzBaseline = Import-AlzBaseline -CsvData $polCsv -AlzInitiatives $alzInitiatives -SelectedInitiatives $SelectedAlzInitiatives Write-Verbose " ALZ baseline policies: $($alzBaseline.Count)" } # Step 2: Get MCSB baseline if requested if ($IncludeMcsb) { Write-Verbose "Retrieving MCSB baseline from Azure..." # Verify Az context try { $context = Get-AzContext if (-not $context) { Write-Warning "No Azure context found. MCSB baseline requires authentication." Write-Warning "Run Connect-AzAccount to authenticate." throw "Azure authentication required for MCSB baseline" } } catch { throw "Failed to get Azure context: $($_.Exception.Message)" } # Use module-scoped caches (persistent across calls) $mcsbBaseline = Import-McsbBaseline -InitiativeDisplayName "Microsoft cloud security benchmark" ` -PolicyDefinitionCache $script:PolicyDefinitionCache ` -PolicySetDefinitionCache $script:PolicySetCache Write-Verbose " MCSB baseline policies: $($mcsbBaseline.Count)" } # Step 3: Merge baselines Write-Verbose "Merging baselines..." $baseline = Merge-PolicyBaselines -AlzBaseline $alzBaseline -McsbBaseline $mcsbBaseline Write-Verbose " Merged baseline: $($baseline.Count) policies" # Step 4: Create indexes Write-Verbose "Creating baseline indexes..." $baselineIndex = New-BaselineIndex -Baseline $baseline # Return result $result = [PSCustomObject]@{ Policies = $baseline Index = $baselineIndex } Write-Debug "Get-AzPolicyBaseline: Completed successfully" return $result } catch { Write-Error "Failed to retrieve policy baseline: $($_.Exception.Message)" throw } } } |