Get-Mailbox combine with Get-MailboxStatistics

My below script works fine but runs slow. I need to run with -resultsize unlimited. when I run it with -resultsize 550 users it takes 12 minutes to finish. What can I change in my code to run it faster.

Note: I shorten the last line $Results

Thank you!

$DataPath = "C:\temp85\o365UserData.csv"
$Results = @()
$MailboxUsers = get-EXOmailbox -resultsize 550

foreach($user in $mailboxusers)
{
$UPN = $user.userprincipalname
$License = Get-MsolUser -userprincipalname $UPN
$MbxStats = Get-EXOMailboxStatistics $UPN

$Properties = @{
Name = $user.name
UPN = $UPN
Alias = $user.alias
#     UsageLocation = $user.usagelocation
License = $License.Licenses[0].AccountSkuId
#     ArchiveStatus = $user.archivestatus
LitigationHoldEnabled = $user.LitigationHoldEnabled
LitigationHoldDate = $User.LitigationHoldDate
LitigationHoldOwner = $User.LitigationHoldOwner
LitigationHoldDuration = $User.LitigationHoldDuration
RetentionPolicy = $user.RetentionPolicy
RetentionHoldEnabled = $User.RetentionHoldEnabled
ExchangeGuid = $user.ExchangeGuid
SamAccountName = $User.SamAccountName
Office = $user.Office
InPlaceHolds = $User.InPlaceHolds
IsInactiveMailbox = $User.IsInactiveMailbox
IsSoftDeletedByRemove = $User.IsSoftDeletedByRemove
IsSoftDeletedByDisable = $User.IsSoftDeletedByDisable
AccountDisabled = $User.AccountDisabled
OrganizationalUnit = $User.OrganizationalUnit
DisplayName = $User.DisplayName
PrimarySmtpAddress = $User.PrimarySmtpAddress
RecipientTypeDetails = $User.RecipientTypeDetails
WhenCreated = $User.WhenCreated
WhenMailboxCreated = $User.WhenMailboxCreated
WhenSoftDeleted = $User.WhenSoftDeleted
#     ServerName = $MbxStats.servername
#     DatabaseName = $MbxStats.databasename
TotItemSize = $MbxStats.totalitemsize
ItemCount = $MbxStats.ItemCount
}

$Results += New-Object psobject -Property $properties

}

$Results | Select-Object Name,DisplayName,License......,License | Export-Csv -notypeinformation -Path $DataPath

It’s not just the size, but For loops in general are always slow. Well, that is depending on what type of For loop you are using, well, that is associated with what PS version you are running as well. Once you throw a large array at it as your are, well, same thing.

So, one option is to chuck the request, just as ADDS does anyway. ADDS has a default count of 1K objects per page, and if you want more, you have to change that settings and understand the impact of that. Also, depending on how many you really have, even TechNet recommends not running it on more than 3K mailboxes at a time.

The other option is to use parallel processing, runspaces, workflows. This still entails break your stuff into chunks though.

Yet when using this construct…

+=

… you really want o understand that impact as well. See this…

https://powershell.org/2013/09/16/powershell-performance-the-operator-and-when-to-avoid-it
 

See also:

Slow Code: Top 5 Ways to Make Your PowerShell Scripts Run Faster
Slow Code: Top 5 Ways to Make Your PowerShell Scripts Run Faster | Microsoft Learn

Why cant PowerShell run loops fast ?
Why cant PowerShell run loops fast ? | Microsoft Learn

Hi

Try following, might not be so much faster. Basically you can skip the whole $Results and pipe the forEach loop to Export-csv also.

Also, measure which one is faster foreach($user in $mailboxusers) or $mailboxusers | ForEach {}

$DataPath = "C:\temp85\o365UserData.csv"
$Results = New-Object System.Collections.Generic.List[System.Object]
$MailboxUsers = get-EXOmailbox -resultsize 550

foreach($user in $mailboxusers) {

$UPN = $user.userprincipalname
$License = Get-MsolUser -userprincipalname $UPN
$MbxStats = Get-EXOMailboxStatistics $UPN

$Results.add([PSCustomObject]@{
    Name = $user.name
    UPN = $UPN
    Alias = $user.alias
    #     UsageLocation = $user.usagelocation
    License = $License.Licenses[0].AccountSkuId
    #     ArchiveStatus = $user.archivestatus
    LitigationHoldEnabled = $user.LitigationHoldEnabled
    LitigationHoldDate = $User.LitigationHoldDate
    LitigationHoldOwner = $User.LitigationHoldOwner
    LitigationHoldDuration = $User.LitigationHoldDuration
    RetentionPolicy = $user.RetentionPolicy
    RetentionHoldEnabled = $User.RetentionHoldEnabled
    ExchangeGuid = $user.ExchangeGuid
    SamAccountName = $User.SamAccountName
    Office = $user.Office
    InPlaceHolds = $User.InPlaceHolds
    IsInactiveMailbox = $User.IsInactiveMailbox
    IsSoftDeletedByRemove = $User.IsSoftDeletedByRemove
    IsSoftDeletedByDisable = $User.IsSoftDeletedByDisable
    AccountDisabled = $User.AccountDisabled
    OrganizationalUnit = $User.OrganizationalUnit
    DisplayName = $User.DisplayName
    PrimarySmtpAddress = $User.PrimarySmtpAddress
    RecipientTypeDetails = $User.RecipientTypeDetails
    WhenCreated = $User.WhenCreated
    WhenMailboxCreated = $User.WhenMailboxCreated
    WhenSoftDeleted = $User.WhenSoftDeleted
    #     ServerName = $MbxStats.servername
    #     DatabaseName = $MbxStats.databasename
    TotItemSize = $MbxStats.totalitemsize
    ItemCount = $MbxStats.ItemCount
})


}

$Results | Export-Csv -notypeinformation -Path $DataPath -Delimiter ';'

Regards

Jake

Not sure if this is faster, but this is how I would do it. Hmm, “-not” is a different color.

$DataPath = "C:\temp85\o365UserData.csv"

get-EXOmailbox -resultsize 550 | foreach-object {
  $user = $_

  $UPN = $user.userprincipalname
  $License = Get-MsolUser -userprincipalname $UPN
  $MbxStats = Get-EXOMailboxStatistics $UPN

  [pscustomobject]@{
    Name = $user.name
    UPN = $UPN
    Alias = $user.alias
    # ...
  } 

} | Export-Csv -notypeinformation -Path $DataPath