<#
.Synopsis
Deletes subfolders that do not contain any items.
.Description
Given a mailbox folder, immediate subfolders that do not contain any items will be deleted.
.Parameter Identity
Mailbox identity to act on.
.Parameter FolderScope
Valid FolderScope value from Get-MailboxFolderStatistics cmdlet, excluding All.
This is the parent folder to use for empty subfolders.
.Parameter FolderPath
The path to the folder, including the foward slash prefix. This is the parent
folder to use for empty subfolders.
.Parameter ExcludeFoldersWithSubFolders
Switch to indicate that any subfolder of the parent folder that itself has subfolders
should not be included for deletion. This is because the subfolder may contain
items that would also be deleted.
.Example
.\Remove-EmptySubfolder.ps1 JohnDoe -FolderScope DeletedItems
.Example
(Get-Mailbox) | .\Remove-EmptySubfolder.ps1 -FolderPath "/Inbox/Folder1"
.Notes
Version: 1.0
Date: 8/30/13
#>
param
(
[Parameter(ValueFromPipeline=$true,Position=0)][string]$Identity,
[Parameter(Mandatory=$true,ParameterSetName='folderscope')]
[ValidateSet('Calendar','Contacts','ConversationHistory','DeletedItems','Drafts',
'Inbox','JunkEmail','Journal','ManagedCustomFolder','Notes','Outbox','Personal',
'RecoverableItems','RssSubscriptions','SentItems','SyncIssues','Tasks')][string]$FolderScope,
[Parameter(Mandatory=$true,ParameterSetName='folderpath')]
[ValidatePattern('(?# Path must begin with / and not end with /)^/.*[^/]$')][string]$FolderPath,
[switch]$ExcludeFoldersWithSubfolders
)
begin {
#Paths to EWS Managed API DLL
$ewsAPIPaths = "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll",
"C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll",
"C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll",
"C:\Program Files\Microsoft\Exchange\Web Services\1.0\Microsoft.Exchange.WebServices.dll"
#Test if any version of API is installed
foreach ($path in $ewsAPIPaths)
{
if (Test-Path -Path $path)
{
Add-Type -Path $path
$apiFound = $true
break
}
}
if (-not($apiFound))
{
Write-Error -Message 'The Exchange Web Services Managed API is required to run this script.' -Category NotInstalled
break
}
}
process {
$EmailAddress = (Get-Mailbox -Identity $Identity).PrimarySMTPAddress
#Get EMS folder ID
if ($FolderScope)
{
$EMSFolder = Get-MailboxFolderStatistics -Identity $Identity -FolderScope $FolderScope | Select-Object -First 1
$EMSFolderId = $EMSFolder.FolderId
}
else
{
$EMSFolder = Get-MailboxFolderStatistics -Identity $Identity | Where-Object {$_.FolderPath -eq $FolderPath}
if ($EMSFolder)
{
$EMSFolderId = $EMSFolder.FolderId
}
else
{
Write-Output -InputObject "$EmailAddress`: No matching parent folder"
break
}
}
#Convert folder ID from EMS to folder ID used by EWS
$EMSFolderId = $EMSFolderId.Replace('+','%2b')
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$ExchangeService = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
$ExchangeService.AutodiscoverUrl($EmailAddress,{$true})
#Uncomment to use impersonation instead of FMA
#$ExchangeService.ImpersonatedUserId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress)
$aiItem = New-Object -TypeName Microsoft.Exchange.WebServices.Data.AlternateId
$aiItem.Mailbox = $EmailAddress
$aiItem.UniqueId = $EMSFolderId
$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::OwaId
$convertedId = $ExchangeService.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EwsId)
$EWSFolderId = $convertedId.UniqueId
#Bind to folder with specific ID
$FolderId = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderId($EWSFolderId)
$TargetFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($ExchangeService,$FolderId)
#Create view large enough to hold all of the search results to avoid paging
$FolderView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.FolderView(850)
#Search filter for folders with no contents
$SearchFilter1 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::TotalCount,0)
$SearchFilter = $SearchFilter1
if ($ExcludeFoldersWithSubfolders)
{
$SearchFilter2 = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::ChildFolderCount,0)
$SearchFilterCollection = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)
$SearchFilterCollection.Add($SearchFilter1)
$SearchFilterCollection.Add($SearchFilter2)
$SearchFilter = $SearchFilterCollection
}
$SearchResults = $ExchangeService.FindFolders($TargetFolder.Id,$SearchFilter,$FolderView)
if ($SearchResults.TotalCount -gt 0)
{
foreach ($folder in $SearchResults.Folders)
{
#Exclude indirect subfolders
if ($folder.ParentFolderId.UniqueId -eq $EWSFolderId)
{
Write-Output -InputObject "$EmailAddress`: $($folder.DisplayName)"
$folder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
}
}
else
{
Write-Output -InputObject "$EmailAddress`: No subfolders to delete"
}
}
end {}