What changed: the original article mixed the Azure Az module with AzureAD cmdlets. This revision uses Microsoft Graph for identity queries and separate connections for Exchange Online and SharePoint Online.
Choose the module for the service
Microsoft 365 is not one PowerShell connection. Installing a module adds its commands; authentication creates a session for the relevant service. Connecting to Graph does not connect you to Exchange Online.
| Task | Module | Connection |
|---|---|---|
| Entra users and identity queries | Microsoft.Graph | Connect-MgGraph |
| Exchange Online recipients and mailboxes | ExchangeOnlineManagement | Connect-ExchangeOnline |
| SharePoint Online tenant administration | Microsoft.Online.SharePoint.PowerShell | Connect-SPOService |
| Azure resource administration | Az | Connect-AzAccount |
The Az module is useful for Azure resource management. Installing it does not provide Connect-AzureAD. For new identity scripts, follow the current Graph or Entra PowerShell guidance instead of copying legacy AzureAD examples.
Environment and permissions
Use a Windows administration machine. Windows PowerShell 5.1 provides a common baseline for the examples here; verify each module’s requirements before using PowerShell 7 or another operating system.
Check the tenant before exporting any data. Graph scopes, directory roles and Exchange role assignments are separate controls; obtaining one type of access does not grant every service permission.
$PSVersionTable.PSVersion
Get-Module Microsoft.Graph*, ExchangeOnlineManagement,
Microsoft.Online.SharePoint.PowerShell -ListAvailable |
Select-Object Name, Version1. Install and connect to Microsoft Graph
The following example uses delegated authentication for a user report. User.Read.All is a read permission and requires administrator consent. Ask the tenant administrator to approve the appropriate access rather than expanding permissions just to bypass an error.
Install-Module Microsoft.Graph -Scope CurrentUser
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Users
Connect-MgGraph -Scopes 'User.Read.All'
Get-MgContext | Select-Object TenantId, Account, ScopesConfirm that the account and tenant shown are the ones you intend to query. For unattended jobs, design an app-authentication workflow separately; do not put interactive credentials into a scheduled script.
Read a single user
Select only the fields needed for the task. Graph returns a default subset of user properties, so request additional fields explicitly.
Get-MgUser -UserId 'user@example.com' `
-Property Id, DisplayName, UserPrincipalName, AccountEnabled |
Select-Object Id, DisplayName, UserPrincipalName, AccountEnabledExport a user report
-All follows result pages. Without it, a successful response may still be only part of the directory. The folder below is a local example; choose a suitably protected destination for a real export.
$reportFolder = Join-Path $env:USERPROFILE 'M365Reports'
New-Item -Path $reportFolder -ItemType Directory -Force | Out-Null
$users = Get-MgUser -All -Property Id, DisplayName, UserPrincipalName, AccountEnabled
$users |
Select-Object Id, DisplayName, UserPrincipalName, AccountEnabled |
Export-Csv (Join-Path $reportFolder 'Users.csv') -NoTypeInformation -Encoding UTF8
$users.CountTo list accounts whose enabled property is false:
$users | Where-Object { $_.AccountEnabled -eq $false } |
Select-Object DisplayName, UserPrincipalName, AccountEnabledThis is a disabled-account report, not a complete inactivity or access-risk assessment. It does not establish when the person last signed in or whether they still have other access paths.
2. Connect to Exchange Online
Install-Module ExchangeOnlineManagement -Scope CurrentUser
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName 'admin@example.com'Use an account with the Exchange permissions needed for the report. The identity query above and this Exchange connection are independent.
Retrieve all mailboxes
Set the result size explicitly before using the output as an inventory or count. A limited default result set can make a report look complete when it is not.
$mailboxes = @(Get-EXOMailbox -ResultSize Unlimited)
$mailboxes.Count
$mailboxes |
Select-Object DisplayName, UserPrincipalName, RecipientTypeDetails |
Export-Csv (Join-Path $reportFolder 'Mailboxes.csv') -NoTypeInformation -Encoding UTF8If you did not run the user-report section, create $reportFolder first. Review the recipient types included and decide whether archives, shared mailboxes or another subset need a separate report.
Check a mailbox’s statistics
Get-EXOMailboxStatistics -Identity 'user@example.com' |
Select-Object DisplayName, ItemCount, TotalItemSizeTotalItemSize is useful for viewing the service’s size output. Do not assume its displayed value is a simple number of bytes when building calculations or sorting a spreadsheet numerically.
Export mailbox statistics with visible failures
For a larger report, preserve the mailbox identity and flag errors rather than silently dropping rows. This makes it easier to distinguish an empty result from a failed query.
$rows = foreach ($mailbox in $mailboxes) {
try {
$stats = Get-EXOMailboxStatistics -Identity $mailbox.UserPrincipalName -ErrorAction Stop
[pscustomobject]@{
UserPrincipalName = $mailbox.UserPrincipalName
DisplayName = $mailbox.DisplayName
ItemCount = $stats.ItemCount
TotalItemSize = [string]$stats.TotalItemSize
Status = 'OK'
}
}
catch {
[pscustomobject]@{
UserPrincipalName = $mailbox.UserPrincipalName
DisplayName = $mailbox.DisplayName
ItemCount = $null
TotalItemSize = $null
Status = 'Query failed: ' + $_.Exception.Message
}
}
}
$rows | Export-Csv (Join-Path $reportFolder 'MailboxStatistics.csv') -NoTypeInformation -Encoding UTF8Start with one mailbox or a small approved subset before querying the entire tenant. Service throttling, permissions and mailbox state can all affect a large run.
3. Connect to SharePoint Online
Use the SharePoint Online management module and your actual tenant administration URL. A SharePoint administrator role may be required for the tenant-level command you intend to run.
Install-Module Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser
Import-Module Microsoft.Online.SharePoint.PowerShell
Connect-SPOService -Url 'https://yourtenant-admin.sharepoint.com'A OneDrive personal-site provisioning request is a change, not a read-only report. If you need it, verify licensing and eligibility, then submit the request for the intended user:
# Change operation: adapt and run only for the approved user.
# Request-SPOPersonalSite -UserEmails 'user@example.com'The request is asynchronous. A returned command does not prove that the personal site is ready; verify the provisioned site separately before depending on it in a migration.
Troubleshooting and validation
A command is not recognised
Check that the module providing it is installed and imported. Do not install Az expecting it to supply Microsoft Graph, Exchange or SharePoint administration commands.
Graph reports insufficient privileges
Check Get-MgContext, the scopes requested, administrator consent and the signed-in identity. Select the permission required for the task rather than granting broad write access to run a read report.
The mailbox count looks too small
Check -ResultSize Unlimited, tenant selection and the recipient types you intended to include. Compare with an independent view of the same scope.
The export exists but data is missing
Check source counts, filter logic and the failed-query rows. Confirm the requested properties were returned before treating a blank field as a real missing value.
Disconnect when finished
Disconnect-MgGraph
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-SPOServiceRun each disconnect command only for the service you connected to. The read-only reports above require no directory rollback; any provisioning action should have its own change plan.
References and revision notes
This revision removes the mixed legacy module setup, makes result paging explicit and adds validation and error reporting. It is a documentation-based revision, not a claim of testing in your tenant.
Infrastructure · Identity · Automation