DeleteSearchFolders.psm1
<#
. [COPYRIGHT] . © 2011-2017 Microsoft Corporation. All rights reserved. . . [DISCLAIMER] . This sample script is not supported under any Microsoft standard support . program or service. The sample scripts are provided AS IS without warranty of . any kind. Microsoft disclaims all implied warranties including, without . limitation, any implied warranties of merchantability or of fitness for a . particular purpose. The entire risk arising out of the use or performance of . the sample scripts and documentation remains with you. In no event shall . Microsoft, its authors, or anyone else involved in the creation, production, . or delivery of the scripts be liable for any damages whatsoever (including, . without limitation, damages for loss of business profits, business . interruption, loss of business information, or other pecuniary loss) arising . out of the use of or inability to use the sample scripts or documentation, . even if Microsoft has been advised of the possibility of such damages. . . [AUTHOR] . Jason Parker, Senior Consultant . . [CONTRIBUTORS] . . . [MODULE] . DeleteSearchFolders.psm1 . . [VERSION] . 1.0 . . [VERSION HISTORY / UPDATES] . 1.0 - Jason Parker . Original Release . #> Function Global:_GetImpersonator { <# .SYNOPSIS Creates an Exchange Web Service object used for impersonating a user's Exchange mailbox. .DESCRIPTION Used to create an impersonated service object using Exchange Web Services for the purpose of accessing information from an Exchange mailbox. .PARAMETER Identity The SMTP Address of the mailbox to be impersonated. .PARAMETER ImpersonatorAccountName The UserPrincipalName of the account that has Application Impersonation Rights to the Exchange environment where the user's mailbox resides. .PARAMETER ImpersonatorAccountPassword Password of the ImpersonatorAccountName .PARAMETER Uri The URL for the Exchange Web Service. If not used, will use AutoDiscover to locate the URL. .EXAMPLE Creates an object called $EWSService used to Impersonate jdoe@contoso.com using admin@contoso.com as the account with Impersonation rights. $EWSService = _GetImpersonator -Identity jdoe@contoso.com -AccountImpersonatorName admin@contoso.com -AccountImpersonatorPassword ******** .NOTES - Requires Exchange Web Service Managed API 2.2 - Supports the use of -Verbose output [IMPERSONATION PERMISSIONS] From the Exchange Management Shell, run the New-ManagementRoleAssignment cmdlet to add the permission to impersonate to the specified user: New-ManagementRoleAssignment –Name:impersonationAssignmentName –Role:ApplicationImpersonation –User:ServiceAccount #> [CmdletBinding()] Param ( [String]$Identity = $( $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.Management.Automation.PSArgumentNullException]::New("Identity"), "RequiredParameterNotDefined", [System.Management.Automation.ErrorCategory]::InvalidArgument, $Identity ) ) ), [System.String]$ImpersonatorAccountName = $( $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.Management.Automation.PSArgumentNullException]::New("ImpersonatorAccountName"), "RequiredParameterNotDefined", [System.Management.Automation.ErrorCategory]::InvalidArgument, $ImpersonatorAccountName ) ) ), [System.String]$ImpersonatorAccountPassword = $( $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.Management.Automation.PSArgumentNullException]::New("ImpersonatorAccountPassword"), "RequiredParameterNotDefined", [System.Management.Automation.ErrorCategory]::InvalidArgument, $ImpersonatorAccountPassword ) ) ), [System.URI]$Uri ) BEGIN { TRY { Write-Verbose ("Validating Installation of EWS Managed API") $EWSRegistryPath = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\Exchange\Web Services' | Sort-Object Name -Descending | Select-Object -First 1 -ExpandProperty Name $EWSInstallDirectory = (Get-ItemProperty -Path Registry::$EWSRegistryPath).'Install Directory' $EWSVersion = $EWSInstallDirectory.SubString(($EWSInstallDirectory.Length - 4),3) $EWSDLL = $EWSInstallDirectory + "Microsoft.Exchange.WebServices.dll" If (Test-Path $EWSDLL) { If ($EWSVersion -lt 2.0) { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::New( [System.ArgumentOutOfRangeException]::New("EWS Version is too old, Please install EWS Managed API 2.0 or later"), "EWSVersionOutOfDate", [System.Management.Automation.ErrorCategory]::InvalidResult, $EWSVersion ) ) } Else { Write-Verbose ("EWS Managed API 2.0 or later is INSTALLED") Import-Module $EWSDLL } } Else { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::New( [System.IO.FileNotFoundException]::New("Unable to find EWS Managed API DLL"), "FileNotFound", [System.Management.Automation.ErrorCategory]::ObjectNotFound, $EWSDLL ) ) } } CATCH {$PSCmdlet.ThrowTerminatingError($PSItem)} } PROCESS { TRY { Write-Verbose ("Building SSL Trust Policy") $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider $Compiler=$Provider.CreateCompiler() $Params=New-Object System.CodeDom.Compiler.CompilerParameters $Params.GenerateExecutable=$False $Params.GenerateInMemory=$True $Params.IncludeDebugInformation=$False $Params.ReferencedAssemblies.Add("System.DLL") | Out-Null $TASource=@' namespace Local.ToolkitExtensions.Net.CertificatePolicy { public class TrustAll : System.Net.ICertificatePolicy { public TrustAll() { } public bool CheckValidationResult(System.Net.ServicePoint sp, System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Net.WebRequest req, int problem) { return true; } } } '@ $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource) $TAAssembly=$TAResults.CompiledAssembly $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll") [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll Write-Verbose ("Creating EWS Service Object") [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1); if ([String]::IsNullOrEmpty($Uri)) { Write-Verbose ("Attempting to locate Service URL from Autodiscover") $Service.AutodiscoverUrl($Identity,{$True}) } else {$Service.Url = $Uri.AbsoluteUri} $Service.Credentials = New-Object Net.NetworkCredential($ImpersonatorAccountName, $ImpersonatorAccountPassword) Write-Verbose ("Attemping to Impersonate {0}" -f $Identity) $Service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $Identity) #Increase the timeout to cater for large mailboxes $Service.Timeout = 150000 Return $Service } CATCH {$PSCmdlet.ThrowTerminatingError($PSItem)} } } Function Global:_GetSearchFolders { <# .SYNOPSIS Gets specific Exchange Search folders from an Exchange Web Service impersonation service with the option to delete the Search Folders. .DESCRIPTION There are times when Exchange Search folders prevent an Exchange mailbox from being migrated. Use this function to search for a specific folder by its name (partial) and delete it. This function requires a connection to Exchange using Web Services Impersonation. .PARAMETER Service Required parameter which contains the Exchange Web Service impersonation details. .PARAMETER NameToSearch Specifiy the full or partial name for the Search folder to find. Do not include any wildcard characters. .PARAMETER Delete Switch parameter used to delete the Search folders found. .EXAMPLE Search for and delete Search folders with the name like "OwaFV15" using an Exchange Web Service impersonation service called $EWSService _GetSearchFolders -Service $EWSService -NameToSearch OwaFV15 -Delete .NOTES - Requires Exchange Web Service Managed API 2.2 - Use the _GetImpersonator function to create the $EWSService object - Supports the use of -Verbose output [IMPERSONATION PERMISSIONS] From the Exchange Management Shell, run the New-ManagementRoleAssignment cmdlet to add the permission to impersonate to the specified user: New-ManagementRoleAssignment –Name:impersonationAssignmentName –Role:ApplicationImpersonation –User:ServiceAccount #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High")] Param( $Service = $( $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.Management.Automation.PSArgumentNullException]::New("Service"), "RequiredParameterNotDefined", [System.Management.Automation.ErrorCategory]::InvalidArgument, $Service ) ) ), [String]$NameToSearch, [Switch]$Delete ) TRY { Write-Verbose ("Building Folder Search View") [Microsoft.Exchange.WebServices.Data.FolderView]$View = New-Object Microsoft.Exchange.WebServices.Data.FolderView([System.Int32]::MaxValue) $View.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly) $View.PropertySet.Add([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName) $View.PropertySet.Add([Microsoft.Exchange.WebServices.Data.FolderSchema]::ChildFolderCount) $View.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep Write-Verbose ("Collecting Search Folders") [Microsoft.Exchange.WebServices.Data.FindFoldersResults]$Folders = $Service.FindFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::SearchFolders,$View) Write-Verbose ("Found {0} Search folders" -f $Folders.Folders.count) $MatchingFolders = $Folders | ? {$_.DisplayName -like "$NameToSearch*"} If ($MatchingFolders.Count -gt 0) { Write-Verbose ("{0} Search folders matching '{1}*'" -f $MatchingFolders.Count,$NameToSearch) If ($Delete) { If ($PSCmdlet.ShouldProcess("$($MatchingFolders.Count) Folders","Delete Search Folders")) { Foreach ($Folder in $MatchingFolders) { Write-Verbose ("Deleting {0}" -f $Folder.DisplayName) $Folder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::SoftDelete) } } Else { Write-Warning ("User cancelled the operation!") Return } } Else {Return $MatchingFolders} } Else {Write-Warning ("No Search folders found matching '{0}*'" -f $NameToSearch)} } CATCH {$PSCmdlet.ThrowTerminatingError($PSItem)} } |