PowerShell: Batching operations to avoid throttling.

More and more often we are receiving escalations as well as general questions on how to batch a given command, in order to avoid throttling or long running sessions that terminates with disconnections. While this may be rather straight-forward to implement, at some times it is inconvenient to build a whole script just to execute simple commands.

With this in mind I have crafted the sample below. The goal of this script is to cover basically 3 scenarios:

  1. You need to export a list containing all the PrimarySMTPAddress of the mailboxes in a given Exchange Organization
  2. You need to export a list containing all the PrimarySMTPAddress of the mailboxes in a given Exchange Organization that matches a given criteria
  3. You want to perform an action on these mailboxes that have been exported at step #1 or #2.


The script, at present relies on the following constraints:

  1. FilterStatement: This string (cmdlet) must store the result of its execution in a variable (i.e. $Var)
  2. EvaluationPredicate: its execution must return either $True or $False and it must refer to the variable ($Var) created at the previous step (i.e. $Var.SomeValue -eq $null)
  3. OperationToPerform: each mailbox which needs to be processed must be referred as $Entry.PrimarySMTPAddress (i.e. Set-Mailbox $Entry.PrimarySMTPAddress -AuditEnabled $true)
  4. All variables which as we know starts by $ need to be prefixed with an accent (`) in order for the variable to be passed in correctly.


Here some examples that better explains the capabilities offered. The script is run against Exchange Online in the examples but it can run seamlessly against Exchange on-premise.

The examples relies on $Cred and $Url to be previously populated. A common way to value these would be:

$Cred = (New-Object System.Management.Automation.PSCredential -ArgumentList ('User@Contoso.com'),(ConvertTo-SecureString -AsPlainText 'Password' -Force)
$Url = "https://outlook.office365.com/powershell-liveid/"


I want to find to export all the mailboxes in my organization/tenant.

Note in this case that we’re just using the -Export switch.

.\UniversalBatcher.ps1 -PsURL $Url -Credentials $Cred -Auth Basic -Export -MailboxList ".\MailboxList.csv" -LogFile ".\LogFile.txt"


I want to export all the mailboxes where Clutter is enabled.

Note in this case, additionally to the -Export switch we’re also adding a -FilterStatement  and a -EvaluationPredicate.

.\UniversalBatcher.ps1 -PsURL $Url -Credentials $Cred -Auth Basic -Export -FilterStatement "`$Clutter = Get-mailbox `$Entry.PrimarySmtpAddress | Get-Clutter" -EvaluationPredicate "`$Clutter.IsEnabled -eq `$true" -MailboxList ".\MailboxList.csv" -LogFile ".\LogFile.txt"


I want to disable Clutter for all the mailboxes listed in a CSV file.

This comes handy when you perform a Staged Migration and you have the CSV ready. note the lack of the -Export switch as the CSV file exists and the presence of -ExecuteOperation as well as -OperationToPerform.

.\UniversalBatcher.ps1 -PsURL $Url -Credentials $Cred -Auth Basic -ExecuteOperation -OperationToPerform "Get-mailbox `$Entry.PrimarySMTPAddress | Set-Clutter -Enable `$false" -MailboxList ".\MailboxList.csv" -LogFile ".\LogFile.txt"


I want to disable Clutter for all the mailboxes where the same is enabled.

Note the presence of -Export as well as -ExecuteOperation as well as -OperationToPerform. Optionally you can drop -FilterStatement  and -EvaluationPredicate if you want to execute the command for all mailboxes and not just the ones where Clutter is enabled.

.\UniversalBatcher.ps1 -PsURL $Url -Credentials $Cred -Auth Basic -Export -FilterStatement "`$Clutter = Get-mailbox `$Entry.PrimarySmtpAddress | Get-Clutter" -EvaluationPredicate "`$Clutter.IsEnabled -eq `$true" -ExecuteOperation -OperationToPerform "Get-mailbox `$Entry.PrimarySMTPAddress | Set-Clutter -Enable `$true" -MailboxList ".\MailboxList.csv" -LogFile ".\LogFile.txt"


Some further examples, moving away from Clutter which was taken as example as it offered more room for demonstration.

Remove a forward (set on or ) for any mailbox where these properties have a non $null value.

.\UniversalBatcher.ps1 -PsURL $Url -Credentials $Cred -Auth Basic -Export -FilterStatement "`$Forward = Get-mailbox `$Entry.PrimarySmtpAddress" -EvaluationPredicate "`$Forward.ForwardingAddress -ne `$null -or `$Forward.ForwardingSmtpAddress -ne `$null" -ExecuteOperation -OperationToPerform "Set-Mailbox `$Entry.PrimarySMTPAddress -ForwardingAddress `$null -ForwardingSmtpAddress `$null" -MailboxList ".\MailboxList.csv" -LogFile ".\LogFile.txt"


Export the mailbox statistics for all the mailboxes listed in a CSV file.

As shown before, this can be tweaked, using the correct -FilterStatement  and -EvaluationPredicate to only report on a given department or group of people.

.\UniversalBatcher.ps1 -PsURL $Url -Credentials $Cred -Auth Basic -Export -ExecuteOperation -OperationToPerform "Get-Mailbox `$Entry.PrimarySMTPAddress | Get-MailboxFolderStatistics | Select Identity, Name, FolderPath, FolderType, ItemsInFolder, DeletedItemsInFolder, ItemsInFolderAndSubfolders, DeletedItemsInFolderAndSubfolders, FolderSize, FolderAndSubfolderSize | Export-CSV -NoTypeInformation -Path .\Stats.csv -Append" -MailboxList ".\MailboxList.csv" -LogFile ".\LogFile.txt"


List all the mailboxes where a forward is set, for each fo these generate a CSV file showing the forward settings.

.\UniversalBatcher.ps1 -PsURL $Url -Credentials $Cred -Auth Basic -Export -FilterStatement "`$Forward = Get-mailbox `$Entry.PrimarySmtpAddress" -EvaluationPredicate "`$Forward.ForwardingAddress -ne `$null -or `$Forward.ForwardingSmtpAddress -ne `$null" -ExecuteOperation -OperationToPerform "Get-Mailbox `$Entry.PrimarySMTPAddress | Select DisplayName, PrimarySMTPAddress, ForwardingAddress, ForwardingSmtpAddress, DeliverToMailboxAndForward  | Export-CSV -NoTypeInformation -Path .\Fwd.csv -Append" -MailboxList ".\MailboxList.csv" -LogFile ".\LogFile.txt"


Hope this simplifies batching scripts or executing some operation agaisnt a large pool of mailboxes.

Please feel free to comment if you feel there would be any change or modification which would ease the way you administer Exchange.


Comments (0)

Skip to main content