Private/New-AzureUtilsTagComplianceQuery.ps1
|
function New-AzureUtilsTagComplianceQuery { <# .SYNOPSIS Builds the Resource Graph (KQL) query for required-tag compliance. .DESCRIPTION Pure, side-effect-free. For every resource, accumulates the required tag keys that are missing or empty into a 'missing' array and keeps only the resources that violate at least one requirement. Tag keys are escaped against query injection. .PARAMETER RequiredTag One or more tag keys that every resource must carry (non-empty). .OUTPUTS System.String (the KQL query) #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string[]] $RequiredTag ) # Escape a value for use inside a single-quoted KQL string literal. $escape = { param($value) ($value -replace '\\', '\\') -replace "'", "\'" } $lines = [System.Collections.Generic.List[string]]::new() $lines.Add('resources') $lines.Add('| extend __missing = dynamic([])') foreach ($key in $RequiredTag) { $safe = & $escape $key $lines.Add("| extend __missing = iff(isempty(tostring(tags['$safe'])), array_concat(__missing, dynamic(['$safe'])), __missing)") } $lines.Add('| where array_length(__missing) > 0') $lines.Add("| extend reason = strcat('Missing required tag(s): ', strcat_array(__missing, ', '))") # 'missing' is a reserved identifier in the Resource Graph KQL dialect, so the # projected column is named 'missingTags'. $lines.Add('| project id, name, type, resourceGroup, location, subscriptionId, tags, reason, missingTags = __missing') return ($lines -join "`n") } |