tests/Test-Assessment.21858.ps1

<#
.SYNOPSIS
 
#>


function Test-Assessment-21858 {
    [ZtTest(
        Category = 'External collaboration',
        ImplementationCost = 'Medium',
        MinimumLicense = ('Free'),
        Pillar = 'Identity',
        RiskLevel = 'Medium',
        SfiPillar = 'Protect tenants and isolate production systems',
        TenantType = ('Workforce', 'External'),
        TestId = 21858,
        Title = 'Inactive guest identities are disabled or removed from the tenant',
        UserImpact = 'Low'
    )]
    [CmdletBinding()]
    param(
        $Database
    )

    Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose
    if ( -not (Get-ZtLicense EntraIDP1) ) {
        Add-ZtTestResultDetail -SkippedBecause NotLicensedEntraIDP1
        return
    }

    $activity = 'Checking Inactive guest identities are removed from the tenant'
    Write-ZtProgress -Activity $activity -Status 'Querying enabled guest users'

    $sql = @"
    SELECT id, displayName, userPrincipalName, accountEnabled, externalUserState,
    date_diff('day', signInActivity.lastSuccessfulSignInDateTime, today()) daysSinceLastSignIn,
    date_diff('day', createdDateTime, today()) daysSinceCreated,
    strftime(createdDateTime, '%Y-%m-%d') fmtCreatedDateTime,
    strftime(signInActivity.lastSuccessfulSignInDateTime, '%Y-%m-%d') fmtLastSignInDateTime
    FROM User
    WHERE UserType = 'Guest' AND AccountEnabled = true
"@


    $inactiveGuests = @()
    $enabledGuestUsers = Invoke-DatabaseQuery -Database $Database -Sql $sql

    if ($enabledGuestUsers) {
        $inactivityThresholdDays = 90

        foreach ($guest in $enabledGuestUsers) {
            $daysSinceLastActivity = $null
            $activitySource = ''
            # Fixed issue #593: Check the actual column returned by SQL query, not signInActivity object.
            # Ensure the value is a valid number (handles NULL, DBNull, and empty strings).
            # DuckDB date_diff returns BIGINT, so we check for [long] (and [int] for safety).
            if ($guest.daysSinceLastSignIn -is [int] -or $guest.daysSinceLastSignIn -is [long]) {
                # Use lastSuccessfulSignInDateTime
                $daysSinceLastActivity = $guest.daysSinceLastSignIn
                $activitySource = 'last successful sign-in'
            }
            elseif ($guest.daysSinceCreated -is [int] -or $guest.daysSinceCreated -is [long]) {
                # signInActivity is null, use days since creation
                $daysSinceLastActivity = $guest.daysSinceCreated
                $activitySource = 'creation date (no sign-in activity)'
            }

            # if guests exist with no sign-in activity in the last $inactivityThresholdDays days add them to the list
            if ($null -ne $daysSinceLastActivity -and $daysSinceLastActivity -gt $inactivityThresholdDays) {
                $inactiveGuests += [PSCustomObject]@{
                    Guest                 = $guest
                    DaysSinceLastActivity = $daysSinceLastActivity
                    LastSignInDate        = $guest.fmtLastSignInDateTime
                    CreatedDate           = $guest.fmtCreatedDateTime
                    ActivitySource        = $activitySource
                }
            }
        }
        # Mark as FAIL if inactive guests exist
        if ($inactiveGuests.Count -gt 0) {
            $passed = $false
            $testResultMarkdown = "❌ Found $($inactiveGuests.Count) inactive guest user(s) with no sign-in activity in the last $inactivityThresholdDays days:`n`n%TestResult%"
        }
        else {
            $passed = $true
            $testResultMarkdown = "✅ All enabled guest user(s) have been active within the last $inactivityThresholdDays days."
        }
    }
    else {
        $passed = $true   # Test passes if no enabled guests
        $testResultMarkdown = "No guest users found in the tenant."
    }

    # Build the detailed sections of the markdown

    # Define variables to insert into the format string
    $reportTitle = 'Inactive guest accounts in the tenant'
    $tableRows = ''

    if ($inactiveGuests.Count -gt 0) {
        # Create a here-string with format placeholders {0}, {1}, etc.
        $formatTemplate = @'
 
## {0}
 
 
| Display name | User principal name | Last sign-in date | Created date |
| :----------- | :------------------ | :---------------- | :----------- |
{1}
 
'@


        foreach ($inactiveGuest in $inactiveGuests) {
            $portalLink = 'https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserProfileMenuBlade/~/overview/userId/{0}/hidePreviewBanner~/true' -f $inactiveGuest.guest.id
            $displayName = Get-SafeMarkdown $inactiveGuest.guest.displayName
            $userPrincipalName = $inactiveGuest.guest.userPrincipalName
            $lastSignInDateTime = $inactiveGuest.LastSignInDate
            $createdDateTime = $inactiveGuest.CreatedDate
            $tableRows += "| [$displayName]($portalLink) | $userPrincipalName | $lastSignInDateTime | $createdDateTime |`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             = '21858'
        Status             = $passed
        Result             = $testResultMarkdown
    }
    Add-ZtTestResultDetail @params
}