private/tests/Test-Assessment.21818.ps1

<#
.SYNOPSIS

#>


function Test-Assessment-21818 {
    [CmdletBinding()]
    param(
        $Database
    )

    Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose

    $activity = "Checking Activation alert for highly privileged role assignments"
    Write-ZtProgress -Activity $activity -Status "Getting PIM policy assignments for highly privileged roles"

    $EntraIDPlan = Get-ZtLicenseInformation -Product EntraID
    if ($EntraIDPlan -eq "Free" -or $EntraIDPlan -eq "P1") {
        Write-PSFMessage '🟦 Skipping test: Requires P2 or Governance plan' -Tag Test -Level VeryVerbose
        return
    }

    # Query retrieves the associated PIM role management policy assignments for each highly privileged role
    $sqlPolicyAssignments = @"
SELECT
    rmp.id as policyAssignmentId,
    rmp.roleDefinitionId,
    rmp.scopeId,
    rmp.scopeType,
    rmp.policyId,
    rd.displayName as roleDisplayName,
    rd.isPrivileged
FROM main."RoleManagementPolicyAssignment" rmp
INNER JOIN main."RoleDefinition" rd ON rmp.roleDefinitionId = rd.id
WHERE rd.isPrivileged = true
    AND rmp.scopeId = '/'
    AND rmp.scopeType = 'DirectoryRole'
ORDER BY rd.displayName;
"@

    $resultsPolicyAssignments = Invoke-DatabaseQuery -Database $Database -Sql $sqlPolicyAssignments

    # Define PIM notification settings that should be checked
    $notifications = @(
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when members are assigned as eligible to this role"
            NotificationType     = "Role assignment alert"
            RuleId               = "Notification_Admin_Admin_Eligibility"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when members are assigned as eligible to this role"
            NotificationType     = "Notification to the assigned user (assignee)"
            RuleId               = "Notification_Requestor_Admin_Eligibility"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when members are assigned as eligible to this role"
            NotificationType     = "Request to approve a role assignment renewal/extension"
            RuleId               = "Notification_Approver_Admin_Eligibility"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when members are assigned as active to this role"
            NotificationType     = "Role assignment alert"
            RuleId               = "Notification_Admin_Admin_Assignment"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when members are assigned as active to this role"
            NotificationType     = "Notification to the assigned user (assignee)"
            RuleId               = "Notification_Requestor_Admin_Assignment"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when members are assigned as active to this role"
            NotificationType     = "Request to approve a role assignment renewal/extension"
            RuleId               = "Notification_Approver_Admin_Assignment"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when eligible members activate this role"
            NotificationType     = "Role activation alert"
            RuleId               = "Notification_Admin_EndUser_Assignment"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when eligible members activate this role"
            NotificationType     = "Notification to activated user (requestor)"
            RuleId               = "Notification_Requestor_EndUser_Assignment"
        }
        [PSCustomObject]@{
            NotificationScenario = "Send notifications when eligible members activate this role"
            NotificationType     = "Request to approve an activation"
            RuleId               = "Notification_Approver_EndUser_Assignment"
        }
    )

    $notificationRules = @()
    # This flag is used to control the flow of a loop, allowing the script to break out of the outer loop when set to $true.
    $exitLoop = $false
    $passed = $true

    # Query activation notification rules for administrators
    # For each policy ID, retrieve notification rules for role activation events sent to administrators
    Write-ZtProgress -Activity $activity -Status "Getting activation notification rules"

    foreach ($policyAssignment in $resultsPolicyAssignments) {
        $policyId = $policyAssignment.policyId
        $roleDisplayName = $policyAssignment.roleDisplayName

        foreach ($ruleId in $notifications.ruleId) {
            try {
                $uri = "policies/roleManagementPolicies/$policyId/rules/$ruleId"

                $rule = Invoke-ZtGraphRequest -RelativeUri $uri -ApiVersion 'v1.0' -ErrorAction Stop

                if ($rule) {
                    $notificationRules += ($rule | Add-Member -MemberType NoteProperty -Name RoleDisplayName -Value $roleDisplayName -Force -PassThru)

                    # TO-DO: When the performance of the API is improved, we can collect all rules and move the check outside the loop to determine if the test passes or fails.
                    # Check if isDefaultRecipientsEnabled is true and notificationRecipients is an empty array
                    if ($rule.isDefaultRecipientsEnabled -eq $true -and
                        $rule.notificationRecipients.Count -eq 0) {
                        $passed = $false
                        $exitLoop = $true
                        break  # Exit inner loop if condition is met
                    }
                }
            }
            catch {
                Write-Error "Failed to retrieve rule $ruleId for policy $($policyId): $($_.Exception.Message)"
            }
        }
        if ($exitLoop) {
            break # Exit outer loop if condition is met
        }
    }

    $testResultMarkdown = ""

    # Output the result of the check
    if ($passed) {
        $testResultMarkdown += "Role notifications are properly configured for privileged role.`n`n%TestResult%"
    }
    else {
        $testResultMarkdown += "Role notifications are not properly configured.`n`nNote: To save time, this check stops when it finds the first role that does not have notifications. After fixing this role and all other roles, we recommend running the check again to verify.`n`n%TestResult%"
    }

    # Build the detailed sections of the markdown

    # Define variables to insert into the format string
    $reportTitle = "Notifications for high privileged roles"
    $tableRows = ""

    # Create a here-string with format placeholders {0}, {1}, etc.
    $formatTemplate = @'

## {0}


| Role Name | Notification Scenario | Notification Type | Default Recipients Enabled | Additional Recipients |
| :-------- | :-------------------- | :---------------- | :------------------------- | :-------------------- |
{1}

'@


    foreach ($notificationRule in $notificationRules) {
        $matchingNotification = $notifications | Where-Object { $_.RuleId -eq $notificationRule.id }
        $tableRows += @"
| $($notificationRule.roleDisplayName) | $($matchingNotification.notificationScenario) | $($matchingNotification.notificationType) | $($notificationRule.isDefaultRecipientsEnabled) | $($notificationRule.notificationRecipients -join ', ') |`n
"@

    }

    # Format the template by replacing placeholders with values
    $mdInfo = $formatTemplate -f $reportTitle, $tableRows

    # Replace the placeholder with the detailed information
    $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $mdInfo


    $params = @{
        TestId             = '21818'
        Title              = "Activation alert for highly privileged role assignments"
        UserImpact         = 'Low'
        Risk               = 'High'
        ImplementationCost = 'Low'
        AppliesTo          = 'Identity'
        Tag                = 'Identity'
        Status             = $passed
        Result             = $testResultMarkdown
    }
    Add-ZtTestResultDetail @params
}