PowerShell Conditional Access: Export Azure AD Reports

PowerShell Conditional Access: Export Azure AD Reports

PowerShell Tips Editor 3 min read
PowerShell Conditional Access: Export Azure AD Reports

Monthly security reviews require sign-in logs, MFA registration status, and conditional access policy inventories — all data that lives in Azure AD. Generating PowerShell Azure AD reports manually through the portal is time-consuming and inconsistent. Automating these exports with the Microsoft Graph API gives you repeatable, schedulable reports that go directly to your security team without clicking through the Azure portal each time.

Quick Answer / TL;DR

Connect with Connect-MgGraph -Scopes 'AuditLog.Read.All','Directory.Read.All', then call Get-MgAuditLogSignIn, Get-MgReportAuthenticationMethodUserRegistrationDetail, and Get-MgIdentityConditionalAccessPolicy from the Microsoft.Graph module.

Access Sign-In Logs via Graph API

Sign-in logs are available through the Microsoft.Graph.Reports module. The AuditLog.Read.All permission is required. Azure AD retains sign-in logs for 30 days for free-tier tenants and up to 90 days with Azure AD P1/P2. Export regularly to avoid data loss.

# Install module if needed
Install-Module Microsoft.Graph -Scope CurrentUser -Force

# Connect with required permissions
Connect-MgGraph -Scopes 'AuditLog.Read.All','Directory.Read.All'

# Get sign-ins from last 7 days (filter server-side)
$startDate = (Get-Date).AddDays(-7).ToString('yyyy-MM-ddTHH:mm:ssZ')
$signIns = Get-MgAuditLogSignIn -Filter "createdDateTime ge $startDate" -All

$signIns | Select-Object UserDisplayName, UserPrincipalName,
    CreatedDateTime, AppDisplayName, Status, IpAddress |
    Export-Csv -Path C:\Reports\SignIns_Last7Days.csv -NoTypeInformation

Write-Host "Exported $($signIns.Count) sign-in events"

Get MFA Registration Status

The Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet returns per-user MFA registration details. This is the authoritative source for compliance reporting on which users have registered MFA methods and which have not.

# MFA registration report
$mfaReport = Get-MgReportAuthenticationMethodUserRegistrationDetail -All

$summary = $mfaReport | Select-Object `
    @{N='User';E={$_.UserPrincipalName}},
    @{N='MFARegistered';E={$_.IsMfaRegistered}},
    @{N='MFACapable';E={$_.IsMfaCapable}},
    @{N='Methods';E={$_.MethodsRegistered -join ', '}}

# Export and show stats
$summary | Export-Csv C:\Reports\MFAStatus.csv -NoTypeInformation
$notRegistered = ($summary | Where-Object MFARegistered -eq $false).Count
Write-Host "Users without MFA: $notRegistered of $($summary.Count)"

Export Conditional Access Policy List

Conditional Access policies control access conditions across your tenant. Exporting them as a snapshot provides a baseline for change management and compliance audits.

# Get all Conditional Access policies
$caPolicies = Get-MgIdentityConditionalAccessPolicy -All

$caPolicies | Select-Object `
    DisplayName,
    State,
    @{N='Platforms';E={$_.Conditions.Platforms.IncludePlatforms -join ', '}},
    @{N='Users';E={$_.Conditions.Users.IncludeUsers -join ', '}},
    @{N='Applications';E={$_.Conditions.Applications.IncludeApplications -join ', '}} |
    Export-Csv C:\Reports\ConditionalAccessPolicies.csv -NoTypeInformation

Write-Host "Exported $($caPolicies.Count) CA policies"

Find Guest User Accounts

Guest accounts with stale last-sign-in dates are a common security concern. Query users filtered by UserType eq 'Guest' and sort by last sign-in to identify accounts that have been dormant.

# Find guest users with their last sign-in date
$guests = Get-MgUser -Filter "userType eq 'Guest'" -All `
    -Property DisplayName,UserPrincipalName,SignInActivity,CreatedDateTime

$guestReport = $guests | ForEach-Object {
    [PSCustomObject]@{
        DisplayName       = $_.DisplayName
        UPN               = $_.UserPrincipalName
        Created           = $_.CreatedDateTime
        LastSignIn        = $_.SignInActivity.LastSignInDateTime
        DaysSinceSignIn   = if ($_.SignInActivity.LastSignInDateTime) {
            ((Get-Date) - $_.SignInActivity.LastSignInDateTime).Days
        } else { 'Never' }
    }
}

$guestReport | Sort-Object DaysSinceSignIn -Descending |
    Export-Csv C:\Reports\GuestUsers.csv -NoTypeInformation

Risk Detection Events

Azure AD Identity Protection generates risk detection events for suspicious sign-ins. Exporting these gives your security team actionable intelligence about compromised or at-risk accounts. Requires Azure AD P2 and IdentityRiskEvent.Read.All permission.

# Get risk detections (requires Azure AD P2)
Connect-MgGraph -Scopes 'IdentityRiskEvent.Read.All'

$riskEvents = Get-MgRiskDetection -Filter "riskState eq 'atRisk'" -All

$riskEvents | Select-Object UserDisplayName, UserPrincipalName,
    RiskType, RiskLevel, DetectedDateTime, IpAddress |
    Sort-Object DetectedDateTime -Descending |
    Export-Csv C:\Reports\RiskDetections.csv -NoTypeInformation

Write-Host "Found $($riskEvents.Count) risk events"

Schedule Monthly Report Export

Wrap the reporting logic in a function and schedule it via Windows Task Scheduler. Use a service principal with a client secret for unattended execution — interactive Connect-MgGraph prompts are not suitable for scheduled tasks.

# Connect with app registration (non-interactive)
$tenantId     = $env:AAD_TENANT_ID
$clientId     = $env:AAD_CLIENT_ID
$clientSecret = $env:AAD_CLIENT_SECRET | ConvertTo-SecureString -AsPlainText -Force
$credential   = New-Object System.Management.Automation.PSCredential($clientId, $clientSecret)

Connect-MgGraph -TenantId $tenantId -ClientSecretCredential $credential

# Generate monthly reports
$month = Get-Date -Format 'yyyy-MM'
$path  = "C:\Reports\AzureAD_$month"
New-Item -Path $path -ItemType Directory -Force | Out-Null

# Run report exports here...
Write-Host "Monthly Azure AD report generated in $path"
Disconnect-MgGraph

Common Errors and Fixes

  • AuditLog.Read.All permission required for sign-in logs. Without this Graph API permission, Get-MgAuditLogSignIn returns a 403 Forbidden error. Grant the permission in the Azure AD app registration or request it in the Connect-MgGraph -Scopes list and have a Global Admin consent to it.
  • Sign-in log retention only 30 days in Azure AD — export regularly. Free-tier Azure AD retains sign-in logs for 30 days. Azure AD P1/P2 extends this to 90 days. Schedule automated exports at least monthly (weekly for security-sensitive environments) to maintain a longer history for incident investigations.

Related Cmdlets / See Also

Wrapping Up

Automated Azure AD reporting with PowerShell and Microsoft Graph gives your security team consistent, scheduled data without manual portal work. Start with sign-in logs and MFA status — they answer the most common compliance questions. Schedule exports weekly so you never lose sign-in history to the 30-day retention window.

Send-Item -To