Private/ConvertTo-RoleAssignmentBicep.ps1
|
function ConvertTo-RoleAssignmentBicep { [CmdletBinding()] param( [System.Collections.IDictionary]$SubscriptionData, [System.Collections.IDictionary]$ManagementGroupData ) $bicep_lines = [System.Collections.Generic.List[string]]::new() $bicep_lines.Add("targetScope = 'tenant'") $bicep_lines.Add('') $exported_at_utc = [DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ss'Z'", [Globalization.CultureInfo]::InvariantCulture) $bicep_lines.Add("metadata generatedBy = 'PowerShell.IGA.AccessGuard'") $bicep_lines.Add("metadata exportedAtUtc = '$exported_at_utc'") $bicep_lines.Add('') $format_bicep_string = { param([string]$Value) "'" + $Value.Replace("'", "''").Replace('${', '\${') + "'" } $scope_collections = @( @{ ScopeType = 'ManagementGroup'; ScopeData = $ManagementGroupData; Marker = 'Management Group Role Assignments' } @{ ScopeType = 'Subscription'; ScopeData = $SubscriptionData; Marker = 'Subscription Role Assignments' } ) $allowed_principal_types = @('Device', 'ForeignGroup', 'Group', 'ServicePrincipal', 'User') $seen_assignments = @{} $used_module_names = @{} foreach ($scope_collection in $scope_collections) { $bicep_lines.Add("// MARK: $($scope_collection.Marker)") $bicep_lines.Add('') if ($null -eq $scope_collection.ScopeData) { continue } foreach ($recorded_scope_id in @($scope_collection.ScopeData.Keys | Sort-Object)) { $assignments = @($scope_collection.ScopeData[$recorded_scope_id] | Sort-Object ObjectId, RoleDefinitionName) foreach ($assignment in $assignments) { $principal_id = [string]$assignment.ObjectId $principal_type = [string]$assignment.ObjectType $role_name = [string]$assignment.RoleDefinitionName $display_name = [string]$assignment.DisplayName $sign_in_name = [string]$assignment.SignInName if ([string]::IsNullOrWhiteSpace($principal_id) -or [string]::IsNullOrWhiteSpace($role_name) -or $principal_type -eq 'Unknown' -or $role_name -match '^(?i:unknown|orphaned)(\b|$)' -or $display_name -eq 'Orphaned' -or $sign_in_name -eq 'Orphaned' -or ([string]::IsNullOrWhiteSpace($display_name) -and [string]::IsNullOrWhiteSpace($sign_in_name))) { continue } $assignment_scope = [string]$assignment.Scope $target_scope_type = $null $target_scope_id = $null if ($assignment_scope -match '(?i)^/?subscriptions/([^/]+)$') { $target_scope_type = 'Subscription' $target_scope_id = $Matches[1] } elseif ($assignment_scope -match '(?i)^/?providers/Microsoft\.Management/managementGroups/([^/]+)$') { $target_scope_type = 'ManagementGroup' $target_scope_id = $Matches[1] } elseif (-not $assignment.Inherited) { $target_scope_type = $scope_collection.ScopeType if ($target_scope_type -eq 'Subscription') { if ($recorded_scope_id -match '(?i)^/?subscriptions/([^/]+)$') { $target_scope_id = $Matches[1] } else { $target_scope_id = [string]$recorded_scope_id } } else { if ($recorded_scope_id -match '(?i)^/?providers/Microsoft\.Management/managementGroups/([^/]+)$') { $target_scope_id = $Matches[1] } else { $target_scope_id = [string]$recorded_scope_id } } } if ([string]::IsNullOrWhiteSpace($target_scope_id)) { continue } $assignment_key = '{0}|{1}|{2}|{3}' -f $target_scope_type.ToLowerInvariant(), $target_scope_id.ToLowerInvariant(), $principal_id.ToLowerInvariant(), $role_name.ToLowerInvariant() if ($seen_assignments.ContainsKey($assignment_key)) { continue } $seen_assignments[$assignment_key] = $true $scope_prefix = if ($target_scope_type -eq 'ManagementGroup') { 'mg' } else { 'sub' } $role_name_identifier = [regex]::Replace($role_name.ToLowerInvariant(), '[^a-z0-9]+', '_').Trim('_') $principal_id_identifier = [regex]::Replace($principal_id.ToLowerInvariant(), '[^a-z0-9]+', '_').Trim('_') $module_name = 'mod_role_assignment_{0}_{1}_{2}' -f $scope_prefix, $role_name_identifier, $principal_id_identifier if ($used_module_names.ContainsKey($module_name)) { $scope_id_identifier = [regex]::Replace($target_scope_id.ToLowerInvariant(), '[^a-z0-9]+', '_').Trim('_') $module_name = '{0}_{1}' -f $module_name, $scope_id_identifier $collision_index = 1 while ($used_module_names.ContainsKey($module_name)) { $module_name = '{0}_{1}' -f $module_name, $collision_index $collision_index++ } } $used_module_names[$module_name] = $true $module_reference = if ($target_scope_type -eq 'ManagementGroup') { 'br/public:avm/res/authorization/role-assignment/mg-scope:0.1.2' } else { 'br/public:avm/res/authorization/role-assignment/sub-scope:0.1.1' } $bicep_lines.Add("module $module_name '$module_reference' = {") if ($target_scope_type -eq 'ManagementGroup') { $scope_literal = & $format_bicep_string $target_scope_id $bicep_lines.Add(" scope: managementGroup($scope_literal)") } else { $scope_literal = & $format_bicep_string $target_scope_id $bicep_lines.Add(" scope: subscription($scope_literal)") } $bicep_lines.Add(' params: {') $bicep_lines.Add(" principalId: $(& $format_bicep_string $principal_id)") $bicep_lines.Add(" roleDefinitionIdOrName: $(& $format_bicep_string $role_name)") if ($target_scope_type -eq 'ManagementGroup') { $bicep_lines.Add(" managementGroupId: $scope_literal") } if ($allowed_principal_types -contains $principal_type) { $bicep_lines.Add(" principalType: $(& $format_bicep_string $principal_type)") } $bicep_lines.Add(' enableTelemetry: false') $bicep_lines.Add(' }') $bicep_lines.Add('}') $bicep_lines.Add('') } } } if ($used_module_names.Count -eq 0) { $bicep_lines.Add('// No deployable role assignments were found.') } return ($bicep_lines -join [Environment]::NewLine) + [Environment]::NewLine } |