All scripts
Governance 891
Entra Sign-In Logs Export Report
Pulls Entra ID sign-in logs through Microsoft Graph for a chosen date range, flags failed and risky sign-ins, and exports the whole thing to a CSV you can hand off or review in Excel.
Export-EntraSignInLogsReport.ps1
<#
.SYNOPSIS
Exports Entra ID sign-in logs to a CSV report, with a summary of failed and risky sign-ins.
.DESCRIPTION
Connects to Microsoft Graph and pulls sign-in log entries for a chosen number of days.
The script separates successful sign-ins from failed ones, flags entries marked as risky,
and writes everything to a CSV file so you can review it in Excel or hand it to someone else.
Useful for a quick security check, an access review, or just keeping an eye on unusual
sign-in activity without opening the Entra portal every time.
.PARAMETER DaysBack
How many days of sign-in history to pull. Defaults to 7. The Entra ID free tier only keeps
7 days of sign-in logs, so anything beyond that needs a Premium license.
.PARAMETER OutputPath
Folder to save the CSV report to. Defaults to the current folder.
.PARAMETER FailedOnly
If set, only exports sign-ins that failed, skipping successful ones entirely.
.EXAMPLE
.\Export-EntraSignInLogsReport.ps1 -DaysBack 14 -OutputPath C:\Reports
.EXAMPLE
.\Export-EntraSignInLogsReport.ps1 -FailedOnly
.AUTHOR
Shehryar Hassan
#>
[CmdletBinding()]
param(
[int]$DaysBack = 7,
[string]$OutputPath = ".",
[switch]$FailedOnly
)
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Reports)) {
Write-Host "Installing Microsoft.Graph.Reports module..." -ForegroundColor Yellow
Install-Module Microsoft.Graph.Reports -Scope CurrentUser -Force
}
Import-Module Microsoft.Graph.Reports
Import-Module Microsoft.Graph.Authentication
Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Cyan
Connect-MgGraph -Scopes "AuditLog.Read.All", "Directory.Read.All" -NoWelcome
$startDate = (Get-Date).AddDays(-$DaysBack).ToString("yyyy-MM-ddTHH:mm:ssZ")
$filter = "createdDateTime ge $startDate"
Write-Host "Pulling sign-in logs for the last $DaysBack days, this can take a while for a busy tenant..." -ForegroundColor Cyan
$signIns = Get-MgAuditLogSignIn -Filter $filter -All
if (-not $signIns -or $signIns.Count -eq 0) {
Write-Host "No sign-in log entries found for that period." -ForegroundColor Yellow
return
}
$report = foreach ($entry in $signIns) {
$isFailed = $entry.Status.ErrorCode -ne 0
if ($FailedOnly -and -not $isFailed) { continue }
[PSCustomObject]@{
UserDisplayName = $entry.UserDisplayName
UserPrincipalName = $entry.UserPrincipalName
AppDisplayName = $entry.AppDisplayName
CreatedDateTime = $entry.CreatedDateTime
IPAddress = $entry.IPAddress
City = $entry.Location.City
CountryOrRegion = $entry.Location.CountryOrRegion
Status = if ($isFailed) { "Failed" } else { "Success" }
FailureReason = $entry.Status.FailureReason
RiskLevel = $entry.RiskLevelDuringSignIn
RiskState = $entry.RiskState
ConditionalAccess = $entry.ConditionalAccessStatus
ClientAppUsed = $entry.ClientAppUsed
}
}
$fileName = "EntraSignInLogs_{0}.csv" -f (Get-Date -Format "yyyyMMdd_HHmmss")
$fullPath = Join-Path -Path $OutputPath -ChildPath $fileName
$report | Export-Csv -Path $fullPath -NoTypeInformation
$failedCount = ($report | Where-Object { $_.Status -eq "Failed" }).Count
$riskyCount = ($report | Where-Object { $_.RiskState -and $_.RiskState -ne "none" }).Count
Write-Host ""
Write-Host "Report saved to: $fullPath" -ForegroundColor Green
Write-Host "Total entries: $($report.Count)" -ForegroundColor Green
Write-Host "Failed sign-ins: $failedCount" -ForegroundColor Yellow
Write-Host "Flagged as risky: $riskyCount" -ForegroundColor Yellow
Disconnect-MgGraph | Out-Null
Read it before you run it, and test in a safe tenant first.