ℹ️ Many blog posts do not include full scripts. If you require a complete version, please use the Support section in the menu.
Disclaimer: I do not accept responsibility for any issues arising from scripts being run without adequate understanding. It is the user's responsibility to review and assess any code before execution. More information

Analyzing Entra ID Authentication Methods: A PowerShell Solution

I've recently developed a two-part PowerShell solution to analyze authentication methods across our Entra ID tenant. With the push towards passwordless authentication and MFA adoption, understanding what authentication methods users actually employ has become crucial for security planning. This post walks through both scripts and explains how they work together to provide comprehensive authentication insights.

Visual Images

This is the script running for the last hour as you can see below:


This will the give you a CSV file which you can see here:


Then when you run the html file creator (which I call minigum-reporting.ps1) you get a visual of the login requests and the relevant authentication methods that have actually been used rather than what is registered:


If you scroll a bit further down the page you will then see the logins in searchable format:


If you then wish to search for all the user using SMS notification to login, set the Authentication Method to Text Message:


The chart section will then update to show these SMS users:


Part 1: Extracting Authentication Data from Sign-In Logs

The first script queries Entra ID sign-in logs via the Microsoft Graph API to extract detailed authentication method information. Here's what makes this approach powerful:

Setting Up Authentication

The script uses application-based authentication with a client secret. You'll need to register an app in Entra ID with the appropriate permissions:

# Authentication variables - REPLACE WITH YOUR VALUES
$TenantId = "YOUR-TENANT-ID"
$ClientId = "YOUR-CLIENT-ID"
$ClientSecret = "YOUR-CLIENT-SECRET"

# Get OAuth token
$tokenBody = @{
    Grant_Type    = "client_credentials"
    Scope         = "https://graph.microsoft.com/.default"
    Client_Id     = $ClientId
    Client_Secret = $ClientSecret
}

The app registration requires either AuditLog.Read.All or Directory.Read.All permissions to access the sign-in logs.

Flexible Time Ranges

I've found that different scenarios require different time windows. The script supports multiple timeframes:

[ValidateSet('1Hour', '3Hours', '24Hours', '7Days')]
[string]$TimeFrame = '7Days'

$StartDate = switch ($TimeFrame) {
    '1Hour'   { $EndDate.AddHours(-1) }
    '3Hours'  { $EndDate.AddHours(-3) }
    '24Hours' { $EndDate.AddDays(-1) }
    '7Days'   { $EndDate.AddDays(-7) }
}

I typically take hourly samples intermittently for real-time monitoring, then expand to 24 hours when deeper analysis is needed. Remember that larger time windows in dense tenants will take longer to process - I've seen 7-day queries take 10-15 minutes in organizations with thousands of users.

Accessing the Beta API for Authentication Details

The key to getting authentication method details is using the beta endpoint. The v1.0 API doesn't expose the authenticationDetails property:

$uri = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=createdDateTime ge $startDateStr and createdDateTime le $endDateStr and signInEventTypes/any(t: t eq 'interactiveUser')&`$top=999"

Notice the filter for interactiveUser - this excludes service principal sign-ins which don't have authentication methods.

Processing Authentication Methods

The script captures unique authentication methods per user. This is crucial because users often have different methods on different devices:

foreach ($authDetail in $log.authenticationDetails) {
    # Skip if authentication method is empty or previously satisfied
    if ([string]::IsNullOrWhiteSpace($authDetail.authenticationMethod) -or 
        $authDetail.authenticationMethod -eq 'Previously satisfied') {
        continue
    }
    
    # Create unique key for user and auth method
    $userKey = $log.userPrincipalName
    $authMethod = $authDetail.authenticationMethod
    $deviceInfo = if ($log.deviceDetail.displayName) { 
        $log.deviceDetail.displayName 
    } else { 
        "Unknown Device" 
    }
    
    # Create composite key for unique user/method/device combination
    $uniqueKey = "$userKey|$authMethod|$deviceInfo"

I deliberately ignore "Previously satisfied" results as these don't represent actual authentication events - they're just cached sessions. What I'm interested in are the actual authentication methods users employ when challenged.

Device Identification

An interesting aspect is device naming. If a device is enrolled in Entra ID, you'll see its actual name. Otherwise, it appears as "Unknown Device":

$deviceInfo = if ($log.deviceDetail.displayName) { 
    $log.deviceDetail.displayName 
} else { 
    "Unknown Device" 
}

This helps identify whether users are signing in from managed devices or personal/unmanaged devices.

Output and Results

When the script completes, you get both console output and a CSV file:

# Console output showing totals
$methodCounts | Format-Table -AutoSize

# CSV export with all details
$outputFile = "EntraAuthMethods_$(Get-Date -Format 'yyyyMMdd_HHmmss')_$TimeFrame.csv"
$userAuthMethods.Values | Export-Csv -Path $outputFile -NoTypeInformation

The CSV includes comprehensive details: user information, authentication methods, device details, success/failure status, timestamps, and location data.

Part 2: Creating an Interactive HTML Report

The second script transforms the CSV data into a professional, interactive HTML report. Here's how it works:

Automatic File Discovery

The script automatically finds the most recent CSV file:

if ($CsvPath -eq "*.csv") {
    $latestCsv = Get-ChildItem -Filter "EntraAuthMethods_*.csv" | 
        Sort-Object LastWriteTime -Descending | 
        Select-Object -First 1
}

Embedding Data in HTML

Rather than requiring external files, I embed the data directly in the HTML:

# Convert data to JSON with proper escaping
$jsonData = $data | ConvertTo-Json -Compress -Depth 10

# Embed in JavaScript
$html = @"
<script>
    let allData = $jsonData;
    let filteredData = [...allData];
</script>
"@

This creates a self-contained report file that's easy to share.

Interactive Visualizations

The report uses Chart.js to create four key visualizations:

// Authentication Methods Distribution
const methodCounts = {};
filteredData.forEach(d => {
    methodCounts[d.AuthenticationMethod] = 
        (methodCounts[d.AuthenticationMethod] || 0) + 1;
});

// Success vs Failure Rate
const successCount = filteredData.filter(d => d.Succeeded === 'True').length;
const failureCount = filteredData.filter(d => d.Succeeded === 'False').length;

What I've noticed from these reports is often an alarming number of failed sign-ins that warrant investigation. The visualizations make these patterns immediately apparent.

Dynamic Filtering and Search

The report includes comprehensive filtering capabilities:

function applyFilters() {
    const userFilter = document.getElementById('userFilter').value.toLowerCase();
    const methodFilter = document.getElementById('methodFilter').value;
    const successFilter = document.getElementById('successFilter').value;
    const osFilter = document.getElementById('osFilter').value;
    
    filteredData = allData.filter(row => {
        const userMatch = !userFilter || 
            row.UserPrincipalName.toLowerCase().includes(userFilter) ||
            row.UserDisplayName.toLowerCase().includes(userFilter);
        // ... additional filter logic
    });
}

The user search supports partial name matching, making it easy to find specific users and see all their authentication methods across different devices.

Sortable Data Table

The detailed data table supports column sorting:

function sortTable(column) {
    if (sortColumn === column) {
        sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
    } else {
        sortColumn = column;
        sortDirection = 'asc';
    }
    
    // Special handling for date columns
    if (column === 6) { // Date column
        return sortDirection === 'asc' 
            ? new Date(aVal) - new Date(bVal)
            : new Date(bVal) - new Date(aVal);
    }
}

Pagination for Large Datasets

To handle thousands of records efficiently, the report implements pagination:

const rowsPerPage = 25;
const start = (currentPage - 1) * rowsPerPage;
const end = start + rowsPerPage;
const pageData = filteredData.slice(start, end);

Key Insights and Observations

Running these scripts in production has revealed several interesting patterns:

  1. Multiple Authentication Methods: Many users have different authentication methods on different devices - Windows Hello on laptops but SMS on phones. The script captures these variations by creating unique entries for each user/method/device combination.
  2. Failed Authentication Attempts: I've consistently found a surprising number of failed authentication attempts that often go unnoticed. These could indicate password issues, MFA problems, or even security concerns.
  3. Device Enrollment Gaps: The "Unknown Device" entries quickly highlight devices that aren't enrolled in Entra ID, which might represent security gaps in BYOD scenarios.
  4. Authentication Method Distribution: The visual charts immediately show whether your organization is truly moving towards modern authentication methods or still heavily reliant on passwords.

Practical Usage Tips

  1. Start with short time windows (1-3 hours) during business hours to get a quick snapshot
  2. Use the filtering to investigate specific users reported as having sign-in issues
  3. Export filtered data to share specific findings with security teams
  4. Schedule regular reports to track authentication method adoption over time

Technical Considerations

  • The beta API endpoint is required for authentication details but may change
  • Large tenants may hit API throttling limits with 7-day queries
  • The script handles pagination automatically but each page requires a separate API call
  • Consider running during off-peak hours for large time windows

This solution has become an essential tool in my security toolkit for understanding authentication patterns and identifying potential issues before they become problems. The combination of detailed data extraction and interactive visualization provides both the granular details needed for troubleshooting and the high-level overview required for strategic planning.

Previous Post Next Post

نموذج الاتصال