maester-tests/Maester/Entra/Test-EntraRecommendations.Tests.ps1
|
BeforeDiscovery { try { $EntraRecommendations = Invoke-MtGraphRequest -DisableCache -ApiVersion beta -RelativeUri 'directory/recommendations?$expand=impactedResources' -OutputType Hashtable Write-Verbose "Found $($EntraRecommendations.Count) Entra recommendations" } catch { Write-Verbose 'Authentication needed. Please call Connect-MgGraph.' } } Describe "Maester/Entra" -Tag "Maester", "Entra", "Security", "Recommendation" -ForEach $EntraRecommendations { It "MT.1024: Entra Recommendation - <displayName>. See https://maester.dev/docs/tests/MT.1024" -Tag "MT.1024", $recommendationType { $EntraPremiumRecommendations = @( "insiderRiskPolicy", "userRiskPolicy", "signinRiskPolicy" ) $recommendationUrl = "https://entra.microsoft.com/#view/Microsoft_AAD_IAM/RecommendationDetails.ReactView/recommendationId/$id" $recommendationLinkMd = "`n`n➡️ Open [Recommendation - $displayName]($recommendationUrl) in the Entra admin portal." # The $id looks like "{tenantId}_{recommendationKey}" # Extract the recommendation key (the part after the underscore) $recommendationKey = $id -replace '^[^_]+_', '' $recommendationSequence = @{ "insiderRiskPolicy" = 1 "userRiskPolicy" = 2 "signinRiskPolicy" = 3 "selfServicePasswordReset" = 4 "roleOverlap" = 5 "oneAdmin" = 6 "passwordHashSync" = 7 "pwagePolicyNew" = 8 "mfaRegistrationV2" = 9 "integratedApps" = 10 "blockLegacyAuthentication" = 11 "adminMFAV2" = 12 "servicePrincipalKeyExpiry" = 13 "applicationCredentialExpiry" = 14 "staleAppCreds" = 15 "staleApps" = 16 "aadGraphDeprecationServicePrincipal" = 17 "unusedEnterpriseApps" = 18 } # Get sequential number for current recommendation, default to the key if not found $sequentialNumber = $recommendationKey if ($recommendationSequence.ContainsKey($recommendationKey)) { $sequentialNumber = $recommendationSequence[$recommendationKey] } $recommendationName = $recommendationKey -replace "_", " " $recommendationName = $recommendationName -replace "Policy", "policy" $testTitle = "MT.1024.$($sequentialNumber): Entra Recommendation - $displayName" $EntraIDPlan = Get-MtLicenseInformation -Product "EntraID" if ( $EntraIDPlan -ne "P2" ) { $EntraPremiumRecommendations | ForEach-Object { if ( $id -match "$($_)$" ) { Add-MtTestResultDetail -TestTitle $testTitle -SkippedBecause NotLicensedEntraIDP2 return $null } } } if ( $status -match "dismissed" ) { Add-MtTestResultDetail -TestTitle $testTitle -Description $benefits -SkippedBecause Custom -SkippedCustomReason "This recommendation has been **Dismissed** by an administrator.`n`nIf this test is valid for your tenant you can change its state from **Dismissed** to **Active**. $recommendationLinkMd" return $null } #region Add detailed test description $ActionSteps = $actionSteps | Sort-Object -Property 'stepNumber' | ForEach-Object { $_.text + "[$($_.actionUrl.displayName)]($($_.actionUrl.url))." } $ActionSteps = $ActionSteps -join "`n`n" if ($status -ne 'completedBySystem' -and $impactedResources) { $impactedResourcesList = "`n`n#### Impacted resources`n`n | Status | Name | First detected| `n" $impactedResourcesList += "| --- | --- | --- |`n" foreach ($resource in $impactedResources) { if ($resource.status -eq 'completedBySystem') { $resourceResult = "✅ Pass" } else { $resourceResult = "❌ Fail" } $impactedResourcesList += "| $($resourceResult) | [$($resource.displayName)]($($resource.portalUrl)) | $($resource.addedDateTime) | `n" } } if( $status -eq 'completedBySystem' ) { $deepLink = $recommendationLinkMd } else { $deepLink = "`n`nIf the recommendation is not applicable for your tenant, it can be marked as **Dismissed** for Maester to skip it in the future. $recommendationLinkMd" } $ResultMarkdown = $insights + $deepLink + $impactedResourcesList + "`n`n#### Remediation actions:`n`n" + $ActionSteps Add-MtTestResultDetail -TestTitle $testTitle -Description $benefits -Result $ResultMarkdown #endregion # Actual test $status | Should -Be "completedBySystem" -Because $benefits } } |