public/maester/entra/Test-MtPimAlertsExists.ps1

<#
 .Synopsis
  Checks if PIM alerts exists
 
 .Description
  GET /beta/privilegedAccess/aadroles/resources/$tenantId/alerts
 
 .Example
  Test-MtPimAlertsExists -FilteredAccessLevel "ControlPlane" -AlertId "RolesAssignedOutsidePimAlert"
 
.LINK
  https://mycorp.dev/docs/commands/Test-MtPimAlertsExists
#>

function Test-MtPimAlertsExists {
  [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'Exists is not a plurality')]
  [OutputType([object])]
  [CmdletBinding()]

  param (
    [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
    [ValidateSet("RedundantAssignmentAlert", "RolesAssignedOutsidePimAlert", "SequentialActivationRenewalsAlert", "TooManyGlobalAdminsAssignedToTenantAlert", "StaleSignInAlert")]
    # ID for the alert to test.
    [string[]]$AlertId,

    [Parameter(ValueFromPipelineByPropertyName = $true, Position = 1)]
    [ValidateSet("ControlPlane", "ManagementPlane")]
    # Filter based on Enterprise Access Model Tiering. Can be 'ControlPlane' and/or 'ManagementPlane'.
    [string[]]$FilteredAccessLevel = $null,

    [Parameter(ValueFromPipelineByPropertyName = $true, Position = 2)]
    # Specify break glass accounts to exclude. Defaults to automatic detection based on conditional access policy exclusions.
    [object[]]$FilteredBreakGlass = (Get-MtUser -UserType EmergencyAccess)
  )

  begin {
    $mgContext = Get-MgContext
    $tenantId = $mgContext.TenantId
  }

  process {

    # Get PIM Alerts and store as object to be used in the test
    Write-Verbose "Getting PIM Alerts"
    $Alert = Invoke-MtGraphRequest -ApiVersion "beta" -RelativeUri "privilegedAccess/aadroles/resources/$($tenantId)/alerts" | Where-Object { $_.id -eq $AlertId }

    if ($Alert.Where({$_.isActive -eq "True"}).additionalData) {
      $AffectedRoleAssignments = $Alert.Where({$_.isActive -eq "True"}).additionalData | ForEach-Object {
        $CurrentItem = $_.item
        $result = New-Object psobject
        foreach ($entry in $CurrentItem.GetEnumerator()) {
          $result | Add-Member -MemberType NoteProperty -Name $entry.key -Value $entry.value -Force
        }
        $result
      }
    }

    # Filtering based on (EntraOps) Enterprise Access Model Tiering
    if ($null -ne $FilteredAccessLevel) {
      Write-Verbose "Filtering based on Enterprise Access Model Tiering"
      $EamClassification = Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_EntraIdDirectoryRoles.json' | ConvertFrom-Json -Depth 10
      $FilteredClassification = ($EamClassification | Where-Object { $_.Classification.EAMTierLevelName -eq $FilteredAccessLevel }).RoleId
      $AffectedRoleAssignments = $AffectedRoleAssignments | Where-Object { $_.RoleTemplateId -in $FilteredClassification }
    }

    # Exclude Break Glass from Alerts
    if ($null -ne $FilteredBreakGlass -and $null -ne $AffectedRoleAssignments) {
      $AffectedRoleAssignments | Where-Object { $_.AssigneeId -in $($FilteredBreakGlass).Id } | ForEach-Object {
        Write-Verbose "$($_.AssigneeUserPrincipalName) has been defined as Break Glass and removed from $($Alert.id)"
      }
      $AffectedRoleAssignments = $AffectedRoleAssignments | Where-Object { $_.AssigneeId -notin $($FilteredBreakGlass).Id }
    }

    # Set number of affected Items to value of filtered items (for example, original alert has two affected items, but all of them are break glass and excluded from the test)
    $Alert.numberOfAffectedItems = $AffectedRoleAssignments.Count

    # Create test result and details
    $convertHtmlLinkToMD = '<a.*?href=["'']([^"'']*)["''][^>]*>([^<]*)<\/a>' # Regular expression to detect HTML links
    $testDescription = "
 
**Security Impact**`n`n
$($Alert.securityImpact -replace $convertHtmlLinkToMD, '[$2]($1)')
 
**Mitigation steps**`n`n
$($Alert.mitigationSteps -replace $convertHtmlLinkToMD, '[$2]($1)')
 
**How to prevent**`n`n
$($Alert.howToPrevent -replace $convertHtmlLinkToMD, '[$2]($1)')
"


    $AffectedRoleAssignmentSummary = @()
    $AffectedRoleAssignmentSummary += foreach ($AffectedRoleAssignment in $AffectedRoleAssignments) {
      if ($null -ne $AffectedRoleAssignment.AssigneeDisplayName -or $null -ne $AffectedRoleAssignment.RoleDisplayName) {
        " - $($AffectedRoleAssignment.AssigneeDisplayName) with $($AffectedRoleAssignment.RoleDisplayName) by AssigneeId $($AffectedRoleAssignment.AssigneeId)`n"
      } else {
        " - $($AffectedRoleAssignment.AssigneeName) ($($AffectedRoleAssignment.AssigneeUserPrincipalName))`n"
      }
    }

    if ($Alert.Count -gt "0" -and $AffectedRoleAssignments.Count -gt 0) {
      $testResult = "$($Alert.alertDescription)`n`n
$($AffectedRoleAssignmentSummary)
Get more details from the PIM alert [$($Alert.alertName)](https://portal.azure.com/#view/Microsoft_Azure_PIMCommon/AlertDetail/providerId/aadroles/alertId/$($AlertId)/resourceId/$($tenantId)) in the Azure Portal.
"

    } else {
      $testResult = "All privileged role assignments are managed by PIM. Well done!"
    }

    Add-MtTestResultDetail -Description $testDescription -Result $testResult
    return $Alert
  }
}