ActiveSync Device and User Report for Office 365 D, MT, and Exchange 2010+
Today, I had a customer ask me for an ActiveSync device report. Normally, this is a somewhat simple task (Get-Mailbox | Get-ActiveSyncDevice), but in a large environment with hundreds of domains representing different agencies or business units, that is kind of an unwieldy report to run (as well as including a lot of data for out-of-scope users).
So, here's a new script that hopefully solves that problem for someone else besides me.
The first problem, of course, was creating a dynamic filter that I could pass to a Get-Mailbox or Get-CASMailbox command. In an earlier blog post, I talk about how I solved that problem. So, using the [scriptblock]::Create() method to create a my filter gave me a big chunk of the solution. Instead of having to manually execute a command, I could pass a parameter value to my script that would then be passed to Get-Mailbox -Filter and use server-side filtering to dramatically cut down the number of mailboxes that I would query.
Fun fact: the -Filter parameter in Get-Mailbox and Get-CASMailbox doesn't let you use the -match operator, so you're stuck with "like" and "eq" (and their counterparts).
# begin snip
param (
[Parameter(Mandatory=$false)]
[string]$Domain
)
If ($Domain)
{
If ($Domain.StartsWith("*")) { # Value already starts with an asterisk }
Else { $Domain = "*" + $Domain}
$Filter = [scriptblock]::Create("{EmailAddresses -like `"$Domain`" -and HasActiveSyncDevicePartnership -eq `$True}")
}
If ($Domain)
{
$cmd = "Get-CASMailbox -ResultSize $ResultSize -Filter $Filter -WarningAction SilentlyContinue"
$EASMailboxes = Invoke-Expression $cmd
}
#end snip
With those two filtering parameters (EmailAddresses -like $Domain and HasActiveSyncDevicePartnerShip -eq $true), I was able to cut a query down--even for a domain that has 7,000 mailboxes in an Office 365 tenant with 120,000+ mailboxes to just a minute or two.
From there, building the report was a little more than looping through the $EASMailboxes param and then adding a Get-Mailbox to each object in the $EASMailboxes pipeline to retreive DisplayName and PrimarySmtpAddress (since Get-CASMailbox frustratingly doesn't surface those attributes).
Foreach ($Mailbox in $EASMailboxes)
{
$EASDeviceStatistics = Get-ActiveSyncDeviceStatistics -Mailbox $Mailbox.Identity -WarningAction SilentlyContinue
$MailboxStatistics = Get-Mailbox $Mailbox.Identity | Select DisplayName,PrimarySmtpAddress
Write-Host -NoNewLine "Processing mailbox "; Write-Host -NoNewLine -ForegroundColor Green "[ $($i) / $($TotalEASMailboxes) ]"; Write-Host ", $($MailboxStatistics.DisplayName)"
$j = 1
$TotalEASDevices = $EASDeviceStatistics.Count
If (!($TotalEASDevices)) { $TotalEASDevices = "1" }
Foreach ($EASDevice in $EASDeviceStatistics)
{
Write-Host -NoNewLine " Processing device [ $($j) / $($TotalEASDevices) ] ";Write-Host -NoNewLine -ForegroundColor Green "$($EASDevice.DeviceID)"; Write-Host
$line = New-Object PSObject
Add-Member -InputObject $line -MemberType NoteProperty -Name "DisplayName" -Value $MailboxStatistics.DisplayName
Add-Member -InputObject $line -MemberType NoteProperty -Name "PrimarySmtpAddress" -Value $MailboxStatistics.PrimarySmtpAddress
Foreach ($Column in $EASColumns)
{
Add-Member -InputObject $line -MemberType NoteProperty -Name $Column -Value $EASDevice.$Column
}
Foreach ($Column in $CASColumns)
{
Add-Member -InputObject $line -MemberType NoteProperty -Name $Column -Value $Mailbox.$Column
}
Foreach ($Column in $CASArrayColumns)
{
$ColumnData = $Mailbox.$Column -join ";"
Add-Member -InputObject $line -MemberType NoteProperty -Name $Column -Value $ColumnData
}
$Report += $line
$j++
}
$i++
}
One of the things that I discovered, though, was that I was retrieving data for mailboxes whose PrimarySmtpAddress didn't line up with the domain I had supplied in the -Domain parameter. I was curious about this and decided to investigate--and discovered that those users had a proxyAddress that matched the domain in the filter, but had a different PrimarySmtpAddress (I'm guessing it was to cover reply-ability issues when people moved between agencies or departments).
As to why these objects got included, this would be due to the fun fact from earlier--you can't use the -match operator in the -Filter parameter, and since the PrimarySmtpAddress property of a mailbox isn't returned in Get-CASMailbox, the only one available to use is EmailAddresses.
The final step was to create a switch parameter to determine if the final output should exclude those mailboxes. Fortunately, I can use RegEx here. I just have to take off the pre-pended asterisk in the $Domain variable and run a -match against the PrimarySmtpAddress column of the report object.
If ($ExcludeSecondaryDomains -and $Domain)
{
$PrimarySmtpDomain = $Domain.Substring(1)
$TempReport = $Report | ? { $_.PrimarySmtpAddress -match $PrimarySmtpDomain }
$TempReport | Export-Csv -NoTypeInformation $ReportName
}
Else
{
$Report | Export-Csv -NoTypeInformation $ReportName
}
You can grab the completed report script over on the TechNet Gallery.