Public/Fix-NLBaselineCAPolicyNaming.ps1
|
function Fix-NLBaselineCAPolicyNaming { <# .SYNOPSIS Fix policy naming to match the standard naming convention .DESCRIPTION Identifies and renames policies that don't follow the CA###-{TargetGroup}-{Category}-{Apps}-{Platform}-{Control} naming convention. Matches policies based on their configuration and renames them to the correct baseline naming. .EXAMPLE Fix-NLBaselineCAPolicyNaming .EXAMPLE Fix-NLBaselineCAPolicyNaming -WhatIf #> [CmdletBinding(SupportsShouldProcess)] param( [switch]$WhatIf ) try { # Check connection $context = Get-MgContext -ErrorAction SilentlyContinue if (-not $context -or -not $context.TenantId) { Write-Host "Not connected to Microsoft 365. Connecting..." -ForegroundColor Yellow Write-Host "" $connection = Connect-NLBaselineCA if (-not $connection) { Write-Error "Cannot connect to Microsoft 365" return } } Write-Host "========================================" -ForegroundColor Cyan Write-Host " FIX POLICY NAMING" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" Write-Host "Scanning policies for incorrect naming..." -ForegroundColor Yellow Write-Host "" # Get all policies $policies = Get-AllConditionalAccessPolicies # Direct mapping of known incorrect names to correct names $directNameMappings = @{ "GLOBAL - 1050 - BLOCK - High-Risk Countries" = "CA007-Global-AttackSurfaceReduction-AnyApp-AnyPlatform-BLOCK-HighRiskCountries" "GLOBAL - 2040 - GRANT - Terms of Use (All users)" = "CA008-Global-Compliance-AnyApp-AnyPlatform-TermsOfUse" "GLOBAL - 2056 - GRANT - MFA for Windows Azure Service Management API" = "CA013-Global-IdentityProtection-AzureManagement-AnyPlatform-MFA" "GLOBAL - 2057 - GRANT - MFA for Microsoft Admin Portals" = "CA014-Global-IdentityProtection-AdminPortals-AnyPlatform-MFA" "GLOBAL - 2060 - GRANT - Mobile Apps and Desktop Clients" = "CA011-Global-BaseProtection-MobileDesktop-AnyPlatform-CompliantDevice" } if (-not $policies -or $policies.Count -eq 0) { Write-Host "No policies found." -ForegroundColor Yellow return } # Define mapping of old naming patterns to correct naming # Match exact display names that the user reported $namingMappings = @( @{ Pattern = "^GLOBAL\s*-\s*1050\s*-\s*BLOCK\s*-\s*High-Risk Countries$|^GLOBAL\s*-\s*\d+\s*-\s*BLOCK\s*-\s*High-Risk" CorrectName = "CA007-Global-AttackSurfaceReduction-AnyApp-AnyPlatform-BLOCK-HighRiskCountries" MatchFunction = { param($policy) # Match policies that block high-risk countries $policy.grantControls.builtInControls -contains "block" -and $policy.conditions.locations -and $policy.conditions.locations.excludeLocations -and $policy.conditions.locations.excludeLocations.Count -gt 0 } }, @{ Pattern = "^GLOBAL\s*-\s*2040\s*-\s*GRANT\s*-\s*Terms of Use|^GLOBAL\s*-\s*\d+\s*-\s*GRANT\s*-\s*Terms of Use" CorrectName = "CA008-Global-Compliance-AnyApp-AnyPlatform-TermsOfUse" MatchFunction = { param($policy) # Match policies that require Terms of Use ($policy.grantControls.builtInControls -contains "termsOfUse") -or ($policy.grantControls.termsOfUse -and $policy.grantControls.termsOfUse.Count -gt 0) } }, @{ Pattern = "^GLOBAL\s*-\s*2056\s*-\s*GRANT\s*-\s*MFA for Windows Azure Service Management|^GLOBAL\s*-\s*\d+\s*-\s*GRANT\s*-\s*.*Azure.*Service.*Management" CorrectName = "CA013-Global-IdentityProtection-AzureManagement-AnyPlatform-MFA" MatchFunction = { param($policy) # Match policies for Azure Management API (Windows Azure Service Management) $azureMgmtAppId = "797f4846-ba00-4fd7-ba43-dac1f8f63013" ($policy.conditions.applications.includeApplications -contains $azureMgmtAppId) -or ($policy.conditions.applications.includeApplications -contains "797f4846-ba00-4fd7-ba43-5acf33b5e2c5") -or ($policy.conditions.applications.includeApplications -contains "AzureManagement") } }, @{ Pattern = "^GLOBAL\s*-\s*2057\s*-\s*GRANT\s*-\s*MFA for Microsoft Admin Portals|^GLOBAL\s*-\s*\d+\s*-\s*GRANT\s*-\s*.*Admin Portals" CorrectName = "CA014-Global-IdentityProtection-AdminPortals-AnyPlatform-MFA" MatchFunction = { param($policy) # Match policies for Microsoft Admin Portals ($policy.conditions.applications.includeApplications -contains "MicrosoftAdminPortals") -or ($policy.conditions.applications.includeApplications -contains "Office365" -and $policy.grantControls.builtInControls -contains "mfa") } }, @{ Pattern = "^GLOBAL\s*-\s*2060\s*-\s*GRANT\s*-\s*Mobile Apps and Desktop Clients|^GLOBAL\s*-\s*\d+\s*-\s*GRANT\s*-\s*.*Mobile.*Desktop" CorrectName = "CA011-Global-BaseProtection-MobileDesktop-AnyPlatform-CompliantDevice" MatchFunction = { param($policy) # Match policies for Mobile Apps and Desktop Clients with device compliance ($policy.conditions.clientAppTypes -contains "mobileAppsAndDesktopClients") -and ($policy.grantControls.builtInControls -contains "compliantDevice" -or $policy.grantControls.builtInControls -contains "domainJoinedDevice" -or $policy.grantControls.builtInControls -contains "hybridAzureADJoinedDevice") } } ) # Also check for policies that match old naming patterns $policiesToRename = @() foreach ($policy in $policies) { $currentName = $policy.DisplayName # Check if policy already follows naming convention if ($currentName -match "^CA\d{3}-") { continue } # First check direct name mappings (exact match) $matched = $false if ($directNameMappings.ContainsKey($currentName)) { $policiesToRename += @{ Policy = $policy OldName = $currentName NewName = $directNameMappings[$currentName] Reason = "Direct name mapping" } $matched = $true } # If not matched, try pattern matching if (-not $matched) { foreach ($mapping in $namingMappings) { # Try both case-sensitive and case-insensitive matching if ($currentName -match $mapping.Pattern -or $currentName -imatch $mapping.Pattern) { $policiesToRename += @{ Policy = $policy OldName = $currentName NewName = $mapping.CorrectName Reason = "Matched naming pattern" } $matched = $true break } } } # If not matched by pattern, try to match by configuration if (-not $matched) { foreach ($mapping in $namingMappings) { try { $matchResult = & $mapping.MatchFunction $policy if ($matchResult) { # Check if we haven't already added this policy $alreadyAdded = $policiesToRename | Where-Object { $_.Policy.Id -eq $policy.Id } if (-not $alreadyAdded) { $policiesToRename += @{ Policy = $policy OldName = $currentName NewName = $mapping.CorrectName Reason = "Matched by policy configuration" } $matched = $true break } } } catch { # Skip if matching function fails } } } } if ($policiesToRename.Count -eq 0) { Write-Host "No policies found with incorrect naming." -ForegroundColor Green Write-Host "" return } Write-Host "Found $($policiesToRename.Count) policies with incorrect naming:" -ForegroundColor Yellow Write-Host "" foreach ($item in $policiesToRename) { Write-Host "Policy: $($item.OldName)" -ForegroundColor White Write-Host " Will be renamed to: $($item.NewName)" -ForegroundColor Cyan Write-Host " Reason: $($item.Reason)" -ForegroundColor Gray Write-Host "" } if ($WhatIf) { Write-Host "WhatIf: No changes will be made." -ForegroundColor Yellow return } $confirm = Read-Host "Do you want to rename these policies? (Y/N)" if ($confirm -ne "Y" -and $confirm -ne "y") { Write-Host "Operation cancelled" -ForegroundColor Yellow return } $renamedCount = 0 $errors = @() foreach ($item in $policiesToRename) { try { if ($PSCmdlet.ShouldProcess($item.OldName, "Rename to $($item.NewName)")) { Write-Host "Renaming: $($item.OldName) -> $($item.NewName)" -ForegroundColor Yellow # Check if new name already exists $existingPolicy = $policies | Where-Object { $_.DisplayName -eq $item.NewName -and $_.Id -ne $item.Policy.Id } if ($existingPolicy) { Write-Host " Warning: Policy with name '$($item.NewName)' already exists. Skipping." -ForegroundColor Yellow $errors += "Policy '$($item.OldName)' - target name '$($item.NewName)' already exists" continue } # Update policy using REST API $body = @{ displayName = $item.NewName } | ConvertTo-Json -Depth 10 $invokeCmd = Get-Command Invoke-MgGraphRequest -ErrorAction SilentlyContinue if ($invokeCmd) { Invoke-MgGraphRequest -Method PATCH ` -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/$($item.Policy.Id)" ` -Body $body ` -ContentType "application/json" ` -ErrorAction Stop Write-Host " Renamed successfully" -ForegroundColor Green $renamedCount++ } else { throw "Invoke-MgGraphRequest not available" } } } catch { $errors += "Error renaming $($item.OldName): $_" Write-Host " Error: $_" -ForegroundColor Red } } Write-Host "" Write-Host "========================================" -ForegroundColor Green Write-Host " SUMMARY" -ForegroundColor Green Write-Host "========================================" -ForegroundColor Green Write-Host "Renamed: $renamedCount policies" -ForegroundColor White if ($errors.Count -gt 0) { Write-Host "Errors: $($errors.Count)" -ForegroundColor Red foreach ($error in $errors) { Write-Host " - $error" -ForegroundColor Yellow } } Write-Host "" } catch { Write-Error "Error fixing policy naming: $_" } } |