Simplify user tasks like bulk creation, updates, password resets, deletions, license checks & more — all from one place.
🚀 Launch ToolkitFor IT admins, keeping track of every user in the tenant is critical. From ensuring compliance to verifying license allocation and monitoring account health, a consolidated view of all user accounts saves hours of manual reporting. Instead of pulling the data from the portal, you can automate the process with Graph PowerShell. This script fetches all users in your tenant, compiles their essential details, generates a CSV report, and emails it to administrators or stakeholders.
# ===== Microsoft 365 Tenant Users -> CSV -> Email =====
# Requires: Microsoft.Graph module
# Scopes: User.Read.All, Directory.Read.All, Mail.Send
# -------- Email & Output ----------
$FromUser = "admin@contoso.com" # Sender (must have mailbox)
$ToList = "it-ops@contoso.com;secops@contoso.com" # Recipients (; or , separated)
$Subject = "Tenant Users Inventory Report"
$CsvOutDir = "$env:TEMP"
# -------- Connect to Microsoft Graph ----------
Import-Module Microsoft.Graph -ErrorAction Stop
Connect-MgGraph -Scopes "User.Read.All","Directory.Read.All","Mail.Send"
# -------- Get all users with important properties ----------
$users = Get-MgUser -All -Property `
"id,displayName,userPrincipalName,mail,accountEnabled,createdDateTime,department,jobTitle,usageLocation,userType,assignedLicenses,businessPhones,mobilePhone,lastPasswordChangeDateTime"
# -------- Shape rows for CSV ----------
$rows = $users | ForEach-Object {
$primaryPhone = $null
if ($_.BusinessPhones -and $_.BusinessPhones.Count -gt 0) { $primaryPhone = $_.BusinessPhones[0] }
elseif ($_.MobilePhone) { $primaryPhone = $_.MobilePhone }
[PSCustomObject]@{
UserId = $_.Id
DisplayName = $_.DisplayName
UPN = $_.UserPrincipalName
Mail = $_.Mail
UserType = $_.UserType # Member / Guest
AccountEnabled = $_.AccountEnabled
Department = $_.Department
JobTitle = $_.JobTitle
UsageLocation = $_.UsageLocation
LicenseCount = ($_.AssignedLicenses | Measure-Object).Count
PrimaryPhone = $primaryPhone
CreatedDate = $_.CreatedDateTime
LastPasswordChangeDateTime = $_.LastPasswordChangeDateTime
}
}
# -------- Export to CSV ----------
if (-not (Test-Path -Path $CsvOutDir)) { New-Item -ItemType Directory -Path $CsvOutDir | Out-Null }
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
$csvPath = Join-Path $CsvOutDir ("Tenant_Users_Report_{0}.csv" -f $ts)
$rows | Sort-Object DisplayName | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
# -------- Prepare HTML Body ----------
$totalUsers = ($rows | Measure-Object).Count
$summaryHtml = @"
<html>
<body style='font-family:Segoe UI,Arial,sans-serif'>
<h3>Tenant Users Inventory Report</h3>
<p>Total users: <b>$totalUsers</b></p>
<p>The attached CSV includes: DisplayName, UPN, Mail, UserType, AccountEnabled, Department, JobTitle, UsageLocation, LicenseCount, Phone, CreatedDate, LastPasswordChange.</p>
</body>
</html>
"@
# -------- Prepare Attachment ----------
$fileBytes = [System.IO.File]::ReadAllBytes($csvPath)
$base64Content = [System.Convert]::ToBase64String($fileBytes)
$csvFileName = [System.IO.Path]::GetFileName($csvPath)
$attachment = @{
"@odata.type" = "#microsoft.graph.fileAttachment"
name = $csvFileName
contentBytes = $base64Content
contentType = "text/csv"
}
# -------- Build recipients array (split on ; or ,) ----------
$recipients = @()
$ToList.Split(@(';', ','), [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object {
$addr = $_.Trim()
if ($addr) { $recipients += @{ emailAddress = @{ address = $addr } } }
}
# -------- Prepare and Send Email ----------
$mail = @{
message = @{
subject = "$Subject"
body = @{
contentType = "HTML"
content = $summaryHtml
}
toRecipients = $recipients
attachments = @($attachment)
}
saveToSentItems = $true
}
Send-MgUserMail -UserId $FromUser -BodyParameter $mail
Write-Host "Done. Users report saved at: $csvPath" -ForegroundColor Green
Error | Cause | Solution |
---|---|---|
Authorization_RequestDenied | Insufficient permissions | Use scopes User.Read.All, Directory.Read.All, Mail.Send with admin consent. |
Get-MgUser not recognized | Graph module missing/outdated | Install or update Microsoft.Graph. |
Empty CSV | Filters or properties missing | Verify Graph connection and ensure users exist in tenant. |
Email not delivered | $FromUser not mailbox-enabled | Ensure sender account has a licensed mailbox. |
Split error on recipients | Wrong delimiter | Separate multiple recipients with ; or ,. |
With this Graph PowerShell script, you can generate a comprehensive tenant user inventory report and automatically email it to stakeholders. It eliminates the need for manual exports, ensures administrators always have the latest data, and strengthens compliance, operations, and security posture. By scheduling it regularly, you can make user reporting hands-free and reliable.
© m365corner.com. All Rights Reserved. Design by HTML Codex