# This script requires PowerShell 7 or later for the following reasons:
# 1. The Microsoft Graph PowerShell SDK (Microsoft.Graph module) is designed for PowerShell 7+ and may not work reliably in Windows PowerShell 5.1.
# 2. The SignInActivity property is not returned or accessible in PowerShell 5.1 due to .NET and serialization limitations.
# 3. Modern authentication methods used by Connect-MgGraph are only fully supported in PowerShell 7+.
# 4. Paging and the -All switch for Get-MgUser are more reliable in PowerShell 7+.
# 5. Microsoft is focusing new features and bug fixes for the Graph SDK on PowerShell 7+ only.
# Attempting to run this script in Windows PowerShell 5.1 or earlier will result in errors or missing data.
# Check for PowerShell 7+
if ($PSVersionTable.PSVersion.Major -lt 7) {
Write-Host "ERROR: This script requires PowerShell 7 or later. Please run it in PowerShell 7+ (pwsh.exe)." -ForegroundColor Red
exit 1
}
# Connect to Microsoft Graph with required scopes
Connect-MgGraph -Scopes "User.Read.All", "AuditLog.Read.All"
# Define log file path and organization domain
$logFile = "UserReport_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
$orgDomain = "company.com" # Replace with your organization's primary domain
# Calculate the date 6 months ago
$inactiveThreshold = (Get-Date).AddMonths(-6)
# Initialize log content
Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Starting Azure AD user report."
# Get all users with necessary properties
$allUsers = Get-MgUser -All -Property Id, DisplayName, SignInActivity, AccountEnabled, UserType, UserPrincipalName |
Where-Object { $_.SignInActivity.LastSignInDateTime -and ([datetime]$_.SignInActivity.LastSignInDateTime) -lt $inactiveThreshold -and $_.AccountEnabled -eq $true }
# Categorize users
$guestUsers = @()
$memberUsers = @()
foreach ($user in $allUsers) {
if ($user.UserType -eq 'Guest') {
$guestUsers += $user
} elseif ($user.UserType -eq 'Member') {
$memberUsers += $user
}
}
# Log Guest Users
Add-Content -Path $logFile -Value "`n$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Guest Users (Inactive for 6+ months):"
if ($guestUsers.Count -eq 0) {
$message = "No inactive Guest users found."
Write-Host $message
Add-Content -Path $logFile -Value $message
} else {
foreach ($user in $guestUsers) {
$message = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Guest User: $($user.DisplayName) (ID: $($user.Id), UPN: $($user.UserPrincipalName), Last sign-in: $($user.SignInActivity.LastSignInDateTime))"
Write-Host $message
Add-Content -Path $logFile -Value $message
}
}
# Log Member Users
Add-Content -Path $logFile -Value "`n$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Member Users (Inactive for 6+ months):"
if ($memberUsers.Count -eq 0) {
$message = "No inactive Member users found."
Write-Host $message
Add-Content -Path $logFile -Value $message
} else {
foreach ($user in $memberUsers) {
$message = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Member User: $($user.DisplayName) (ID: $($user.Id), UPN: $($user.UserPrincipalName), Last sign-in: $($user.SignInActivity.LastSignInDateTime))"
Write-Host $message
Add-Content -Path $logFile -Value $message
}
}
# Summary
$totalUsers = $guestUsers.Count + $memberUsers.Count
$summary = "`n$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Summary: Total Inactive Users: $totalUsers (Guests: $($guestUsers.Count), Members: $($memberUsers.Count))"
Write-Host $summary
Add-Content -Path $logFile -Value $summary
# Disconnect from Microsoft Graph
Disconnect-MgGraph