<#
.Synopsis
Get number of items in a mailbox over a given size
.Description
Get number of items in a mailbox over a given size, leveraging the AlItems search folder.
If the folder does not exist, it will be created.
.Parameter EmailAddress
Email address of the mailbox. Accepts pipeline input from Get-Mailbox.
.Parameter EWSUrl
To not use autodiscover, specify the URL to use for EWS.
.Parameter Credential
Provide credentials to use instead of the current user.
.Parameter EWSApiPath
Explicit path to EWS API DLL if it has not been installed via setup routine.
.Parameter UseImpersonation
Switch to specify connection to the mailbox via impersonation instead of
full mailbox access.
.Parameter MaxItemSizeMB
Integer, in megabytes, of the item size that must be exceeded to be included in the count.
Default is 150.
.Parameter DoNotIncludeZeroCountMailboxInOutput
Switch to indicate that a successful search that returns 0 matching items should not be
included in the output.
.Example
Get-MailboxLargeItemCount.ps1 -EmailAddress johndoe@company.com -Credential (get-credential)
.Example
Get-Mailbox johndoe | Get-MailboxLargeItemCount.ps1 -EWSUrl 'https://owa.company.com/ews/exchange.asmx' -UseImpersonation
.Notes
Version: 1.1
Date: 2/10/16
#>
[CmdletBinding()]
param
(
[parameter(Mandatory=$true,Position=0,ValueFromPipelinebyPropertyName=$true)][Alias('PrimarySMTPAddress')][string]$EmailAddress,
#Requires -Version 3
[pscredential]$Credential, #If not using v3+, you can remove the [pscredential] accelerator reference
[string]$EWSUrl,
[string]$EWSApiPath,
[switch]$UseImpersonation,
[int]$MaxItemSizeMB = 150,
[switch]$DoNotIncludeZeroCountMailboxInOutput
)
begin
{
$i = 0
function Get-SearchFolder ($mailbox)
{
$folderIdRoot = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$mailbox)
$folderView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderView(10)
$folderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Shallow
#Property that indicates type of folder
$propFolderType = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(13825,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer)
#Folder property that equates to search folder
$folderSearchFilter1 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo($propFolderType,"2")
$folderSearchFilter2 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,"AllItems")
$folderSearchFilterColl = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)
$folderSearchFilterColl.Add($folderSearchFilter1)
$folderSearchFilterColl.Add($folderSearchFilter2)
if (([Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeService,$folderIdRoot)).EffectiveRights -eq [Microsoft.Exchange.WebServices.Data.EffectiveRights]::None)
{
return 'NoPerm'
}
,$exchangeService.FindFolders($folderIdRoot,$folderSearchFilterColl,$folderView)
}
function Create-SearchFolder ($mailbox)
{
$searchFolder = New-Object Microsoft.Exchange.WebServices.Data.SearchFolder($exchangeService)
#Include all items that have a message class
$folderSearchFilter = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+Exists([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass)
$searchFolder.SearchParameters.SearchFilter = $folderSearchFilter
$searchFolder.SearchParameters.Traversal = [Microsoft.Exchange.WebServices.Data.SearchFolderTraversal]::Deep
#Include all items in the visible folder structure
$msgRootFolderId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
$searchFolder.SearchParameters.RootFolderIds.Add($msgRootFolderId)
$searchFolder.DisplayName = 'AllItems'
#Save the folder in the mailbox root (not visible to users)
$folderIdRoot = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$mailbox)
try
{
$searchFolder.Save($folderIdRoot)
$true
}
catch
{
$false
}
}
function Get-ItemsOverSize ($folder, $maxSize)
{
$itemSizeBytes = ($maxSize.ToString()+'MB')/1l
$searchQuery = "Size:>$itemSizeBytes"
$propertySet = New-Object -TypeName Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly)
$itemView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ItemView(10)
$itemView.PropertySet = $propertySet
,$searchBase.FindItems($searchQuery,$itemView)
}
}
process
{
#Test if any version of API is installed before continuing
if ($EWSApiPath)
{$apiPath = $EWSApiPath}
else
{
$apiPath = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services' |
Sort-Object Name -Descending | Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + 'Microsoft.Exchange.WebServices.dll')
}
if (Test-Path $apiPath)
{
Add-Type -Path $apiPath
}
else
{
Write-Error "The Exchange Web Services Managed API is required to use this script." -Category NotInstalled
break
}
$exchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$exchangeService = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExchangeService($exchangeVersion)
if ($Credential)
{
$exchangeService.Credentials = New-Object -TypeName Microsoft.Exchange.WebServices.Data.WebCredentials($Credential)
}
if ($EWSUrl)
{
$exchangeService.Url = $EWSUrl
}
elseif ($i -eq 0)
{
#Improve autodiscover performance for foreign mailboxes by disabling SCP
$exchangeService.EnableScpLookup = $false
$exchangeService.AutodiscoverUrl($EmailAddress, {$true})
#Cache the autodiscover URL for subsequent objects in the pipeline
$autoEWSUrl = $exchangeService.Url
}
else
{
$exchangeService.Url = $autoEWSUrl
}
if ($UseImpersonation)
{
$exchangeService.ImpersonatedUserId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress)
}
$include = $null
$output = "" | Select-Object 'EmailAddress','ItemsOverSize','Note'
$output.EmailAddress = $EmailAddress
try
{
#Get AllItems search folder
$folderSearchResult = Get-SearchFolder -mailbox $EmailAddress
if ($folderSearchResult -eq 'NoPerm')
{
throw 'Error'
}
try
{
$searchBase = $folderSearchResult.Folders[0]
if ($searchBase)
{
#Search for any items over the limit
$itemSearchResult = Get-ItemsOverSize -folder $searchBase -maxSize $MaxItemSizeMB
if ($itemSearchResult.TotalCount -gt 0)
{
$output.ItemsOverSize = $itemSearchResult.TotalCount
$include = $true
}
elseif ($itemSearchResult.TotalCount -eq 0 -and -not ($DoNotIncludeZeroCountMailboxInOutput))
{
$output.ItemsOverSize = 0
$include = $true
}
}
else #Mailbox is missing the AllItems search folder
{
#Create AllItems search folder
Write-Verbose "Creating search folder for $($EmailAddress)"
if (Create-SearchFolder -mailbox $EmailAddress)
{
$folderSearchResult = Get-SearchFolder -mailbox $EmailAddress
$searchBase = $folderSearchResult.Folders[0]
#Search for any items over the limit
$itemSearchResult = Get-ItemsOverSize -folder $searchBase -maxSize $MaxItemSizeMB
if ($itemSearchResult.TotalCount -gt 0)
{
$output.ItemsOverSize = $itemSearchResult.TotalCount
$include = $true
}
elseif ($itemSearchResult.TotalCount -eq 0 -and -not ($DoNotIncludeZeroCountMailboxInOutput))
{
$output.ItemsOverSize = 0
$include = $true
}
}
else
{
$output.Note = 'ErrorCreatingSearchFolder'
$include = $true
}
}
}
catch {}
}
catch
{
$output.Note = 'ErrorSearchingFolders'
$include = $true
}
if ($include)
{
$output
}
$i++
}