Private/Connect-GraphService.ps1

# Connect-GraphService.ps1
# Authenticates to Microsoft Graph and populates $script:Context.
# Part of the M365-QuickAssess module -- not exported.

function Connect-GraphService
{
    Write-Log "Connecting to Microsoft Graph..."

    try
    {
        Connect-MgGraph -Scopes @(
            "Directory.Read.All",
            "Policy.Read.All",
            "User.Read.All",
            "RoleManagement.Read.Directory",
            "DeviceManagementManagedDevices.Read.All",
            "DeviceManagementConfiguration.Read.All",
            "DeviceManagementServiceConfig.Read.All",
            "DeviceManagementApps.Read.All",
            "Reports.Read.All",
            "Group.Read.All",
            "Team.ReadBasic.All",
            "Channel.ReadBasic.All",
            "AuditLog.Read.All",
            "Files.Read.All",
            "Sites.Read.All",
            "SecurityEvents.Read.All"
        ) -NoWelcome -ErrorAction Stop
    }
    catch
    {
        Write-Log "Graph authentication failed: $( $_.Exception.Message )" "ERROR"
        throw
    }

    # -------------------------------------------------------------------
    # Validate connection by pulling org info
    # -------------------------------------------------------------------
    try
    {
        $org = Get-MgOrganization -ErrorAction Stop
    }
    catch
    {
        Write-Log "Graph connection succeeded but org validation failed: $( $_.Exception.Message )" "ERROR"
        throw
    }

    # -------------------------------------------------------------------
    # Identify tenant
    # -------------------------------------------------------------------
    $tenantName   = ( $org.VerifiedDomains | Where-Object { $_.IsInitial } | Select-Object -ExpandProperty Name )
    $tenantPrefix = $tenantName -split "\." | Select-Object -First 1

    Write-Log "Connected to tenant: $tenantName"

    # -------------------------------------------------------------------
    # Confirm correct tenant with the user
    # Allows up to 3 attempts before aborting
    # -------------------------------------------------------------------
    $maxAttempts = 3
    $attempt     = 0

    do
    {
        $attempt++

        Write-Host ""
        Write-Host "=====================================================================" -ForegroundColor Cyan
        Write-Host " Tenant Detected:" -ForegroundColor Cyan
        Write-Host " $tenantName" -ForegroundColor Yellow
        Write-Host "=====================================================================" -ForegroundColor Cyan
        Write-Host ""

        $response = Read-Host " Continue with this tenant? (Y/N)"

        if ( $response -match "^[Yy]$" )
        {
            break
        }
        elseif ( $response -match "^[Nn]$" )
        {
            if ( $attempt -ge $maxAttempts )
            {
                Write-Log "Maximum tenant selection attempts reached -- aborting" "ERROR"
                try { Disconnect-MgGraph -ErrorAction SilentlyContinue } catch {}
                Write-Host ""
                Write-Host " Maximum attempts reached. Please re-run the assessment." -ForegroundColor Red
                Write-Host ""
                throw "Maximum tenant selection attempts reached."
            }

            Write-Log "User rejected tenant '$tenantName' -- reconnecting (attempt $attempt of $maxAttempts)" "WARN"

            try { Disconnect-MgGraph -ErrorAction SilentlyContinue } catch {}

            Write-Host ""
            Write-Host " Disconnected. Prompting for re-authentication (attempt $attempt of $maxAttempts)..." -ForegroundColor Yellow
            Write-Host ""

            Connect-MgGraph -Scopes @(
                "Directory.Read.All",
                "Policy.Read.All",
                "User.Read.All",
                "RoleManagement.Read.Directory",
                "DeviceManagementManagedDevices.Read.All",
                "DeviceManagementConfiguration.Read.All",
                "DeviceManagementServiceConfig.Read.All",
                "DeviceManagementApps.Read.All",
                "Reports.Read.All",
                "Group.Read.All",
                "Team.ReadBasic.All",
                "Channel.ReadBasic.All",
                "AuditLog.Read.All",
                "Files.Read.All",
                "Sites.Read.All",
                "SecurityEvents.Read.All"
            ) -NoWelcome -ErrorAction Stop

            $org        = Get-MgOrganization -ErrorAction Stop
            $tenantName = ( $org.VerifiedDomains | Where-Object { $_.IsInitial } | Select-Object -ExpandProperty Name )
        }
        else
        {
            Write-Host " Please enter Y or N." -ForegroundColor Yellow
        }

    } until ( $response -match "^[Yy]$" )

    # -------------------------------------------------------------------
    # Populate shared context
    # -------------------------------------------------------------------
    $context = Get-MgContext

    $script:Context.TenantId     = $context.TenantId
    $script:Context.GraphAccount = $context.Account
    $script:Context.TenantPrefix = $tenantPrefix

    Write-Log "Graph context established -- Account: $( $script:Context.GraphAccount ) TenantId: $( $script:Context.TenantId )"
}