All scripts
Microsoft 365 566

ActiveSync Mobile Device Report

Reports on every mobile device connected to a mailbox through Exchange ActiveSync, flagging devices that have not synced in a while so you can spot old phones still holding access after someone leaves, or partnerships that are just dead weight.

Get-ActiveSyncDeviceReport.ps1
<#
.SYNOPSIS
Reports on mobile devices connected to mailboxes via Exchange ActiveSync.

.DESCRIPTION
Connects to Exchange Online and pulls every ActiveSync device partnership across the tenant, including device type, model, last sync time, and access state. Flags anything that has not synced within a chosen number of days, which is usually a phone someone stopped using or a device that should have been removed when they left. Exports the results to CSV.

.AUTHOR
Shehryar Hassan

.EXAMPLE
.\Get-ActiveSyncDeviceReport.ps1 -DaysInactive 90 -ExportPath C:\Reports\ActiveSyncDevices.csv
Reports on devices that have not synced in 90 days or more and exports the results to a CSV file.
#>

param(
    [int]$DaysInactive = 90,
    [string]$ExportPath = ".\ActiveSyncDeviceReport.csv"
)

if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) {
    Write-Host "ExchangeOnlineManagement module not found. Installing..." -ForegroundColor Yellow
    Install-Module ExchangeOnlineManagement -Scope CurrentUser -Force
}

Import-Module ExchangeOnlineManagement

Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan
Connect-ExchangeOnline -ShowBanner:$false

$cutoffDate = (Get-Date).AddDays(-$DaysInactive)
$results = @()

Write-Host "Pulling mobile device partnerships, this can take a while on a large tenant..." -ForegroundColor Cyan

$devices = Get-MobileDevice -ResultSize Unlimited

foreach ($device in $devices) {
    try {
        $stats = Get-MobileDeviceStatistics -Identity $device.Identity -ErrorAction Stop

        $lastSync = $stats.LastSuccessSync
        $isStale = $false
        if ($lastSync -and $lastSync -lt $cutoffDate) {
            $isStale = $true
        }
        if (-not $lastSync) {
            $isStale = $true
        }

        $results += [PSCustomObject]@{
            Mailbox            = $device.UserDisplayName
            DeviceType         = $device.DeviceType
            DeviceModel        = $device.DeviceModel
            DeviceOS           = $device.DeviceOS
            LastSuccessSync    = $lastSync
            DeviceAccessState  = $device.DeviceAccessState
            IsStale            = $isStale
            DaysInactiveCutoff = $DaysInactive
        }
    }
    catch {
        Write-Warning "Could not get stats for device $($device.Identity): $($_.Exception.Message)"
    }
}

$staleCount = ($results | Where-Object { $_.IsStale }).Count
Write-Host "Found $($results.Count) device partnerships, $staleCount look stale or inactive." -ForegroundColor Green

$results | Sort-Object IsStale -Descending | Export-Csv -Path $ExportPath -NoTypeInformation

Write-Host "Report saved to $ExportPath" -ForegroundColor Green

Disconnect-ExchangeOnline -Confirm:$false

Read it before you run it, and test in a safe tenant first.