Purge emails from a mailbox that are protected by a Organizational Hold

Scenario: You need to remove messages from a mailbox, but the mailbox is protected under an Organizational Hold (but it could also be a LitHold or a InPlaceHold). Since the message is currently protected, it will not purge out of the mailbox until the hold is expired, or ever, depending on what type of hold is on the mailbox.


1. Disable the Hold:
You need to remove the mailbox from the Hold. If its an Organizational hold, add them to the exclusion. If its a LitHold or InPlace Hold, disable the hold.

get-mailbox steveman | Select *hold*
get-organizationconfig | Select *Hold*

2. Get the message to the Purges Folder:
Move the email items into the Purges folder. You can do this by any one of the following:

Manual Purging: Deleting the message from the mailbox within the client, then ‘deleting ‘purge’ the message from the Recoverable Deleted Items (Deletions folder).

Search Mailbox – You could use search-mailbox with -deletecontent -force.

New-ComplianceSearch & New-ComplianceSearchAction : You could use a new-compliancesearch with a new-compliancesearchaction -purge -purgetype HardDelete.

MFCMAPI: You could use MFCMAPI to move the message directly to the purges folder.

3. Disable SingleItemRecovery and RetainDeletedItemsFor:
Run the following:
set-mailbox steveman -singleitemrecoveryenabled:$false – retaindeleteditemsfor 0.00:00:00

4. Start the Mailbox Folder Assistant:
start-mailboxfolderassistant steveman

Note: For steps 3 and 4, give time in between the steps for Replication and settings to go into effect.


AADSTS500011: The resource principal named was not found in the tenant

Scenario: If your receive the following error when using Hybrid Modern Authentication for Exchange OnPremises, run the following scriptlet below. Our problem was a misconfigured URL set on the get-clientaccessserver where it was pointing to a Servername, and not our shared namespace.


 Get-MapiVirtualDirectory | FL server,*url*
 Get-WebServicesVirtualDirectory | FL server,*url*
 Get-ClientAccessServer | fl Name, AutodiscoverServiceInternalUri
 Get-OABVirtualDirectory | FL server,*url*
 Get-AutodiscoverVirtualDirectory | FL server,*url*
 Get-OutlookAnywhere | FL server,*url*

450 4.4.317 Cannot connect to remote server [Message=451 5.7.3 StartTLS is required to send mail]

Scenario: After a recent renewal of one of our Exchange On-Premises Certificates in our Exchange Online Hybrid Environment, we noticed a 2 minute delay when messages were sending from Exchange Online to Exchange On-Premises via a custom send connector (not the hybrid connector)

Investigating: After some troubleshooting, we realized the TLS string , $TLSCert = (‘<I>’+$cert.issuer+'<S>’+$cert.subject), was not the exact same than what was configured in various properties on our Exchange On-Premises Servers.

Solution: We ran the following PowerShell to check and set the correct certificate properties. In our specific scenario, it was the send connector (which was no longer able to send email to Exchange Online) and it was our receive connector, which was giving us a 2 minute email delay. I suspect this would have been a bigger issue if we removed the older certificate that it was still pointing to right away.

 #Find the TLSCert Name:
        $Cert = Get-ExchangeCertificate -Thumbprint <thumbprint of new certificate> -server <Exchange Server name>
        $TLSCert = (‘<I>’+$cert.issuer+'<S>’+$cert.subject)

    #Check and set the Transport Server to the new cert:
       Get-transportserver -identity <servername> | Select InternalTransportCertificateThumbprint
       #If the thumbprint is not the new cert, move the SMTP Service, and any other service, to the new certificate
       enable-exchangecertificate -thumbprint <thumbprint> -services SMTP 
    #Check and Set the Send Connector to the new TLS Certificate Name
        Get-SendConnector -identity <Office 365 send Connector> | Select TLSCertificateName
        #If its not using the new cert,  run the following
        Set-SendConnector -Identity <Office 365 send Connector> -TLSCertificateName $TLSCert
    #Check and Set the Receive Connector
        Get-ReceiveConnector "ServerName\Default Frontend ReceiveConnector" | Select TLSCertificateName
        #If its not using the new cert,  run the following
        Get-ReceiveConnector "ServerName\Default Frontend ReceiveConnector" | Set-ReceiveConnector -TlsCertificateName $TLSCert

Cannot delete a Exchange Database because “This mailbox database contains one or more mailboxes, mailbox plans, archive mailboxes, public folder mailboxes or arbitration mailboxes, Audit mailboxes”

Scenario: When attempting to remove an Exchange database, you receive the following error:

This mailbox database contains one or more mailboxes, mailbox plans, archive mailboxes, public folder mailboxes or
arbitration mailboxes, Audit mailboxes.

Scriptlet: Here is a quick script to check that database for mailbox or mailbox data that may be active on it:

$Db = “DB01”
Get-Mailbox -Database $DB
Get-Mailbox -Database $DB -Archive
Get-Mailbox -Database $DB -PublicFolder
Get-Mailbox -Database $DB -Arbitration.
Get-Mailbox -Database $DB -AuditLog
Get-MoveRequest |Where {($_.TargetDatabase -eq $db) -or ($_.SourceDatabase -eq $DB)}


Search-Mailbox: Easy way to convert String values to Integers

Scenario: Need an easy way to convert the [string] value into a number? Specifically for the Search-Mailbox command for the ResultItemsCount and ResultItemsSize?


$Search = Search-Mailbox $mbx -SearchDumpster -SearchQuery Received:1/1/1900..1/1/2013 -EstimateResultOnly

Now convert the results and store in a variable:
Note: $ItemSize is in Bytes.

$ItemCount = ($Search.ResultItemsCount) -as [int]

$ItemSize = (([regex]::match($Search.ResultItemsSize, $regex).Groups[1].value) -replace " bytes","" -as [int])

Checking SCP status during Exchange On-Premise rebuild

Scenario: You are going to build a new Exchange On-Premises server, and you want to monitor the Autodiscover SCP record that is created so you can $null it out BEFORE your customer Outlook email clients start discovering the default server and pulling in the incorrect configuration values for the email clients server settings.

Script: Here is a monitor script that you can use, or build off of, to identify when the SCP record is created and you can go directly into ADSI edit and $null out the ServiceBindingInformation:

$r = @()
$r += get-adobject “CN=ExServer1,CN=Autodiscover,CN=Protocols,CN=ExServer1,CN=Servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),CN=Administrative Groups,CN=Enterprise Exchange,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domain,DC=com” -Properties * | Select CN, objectclass, ServiceBindingInformation
$r += get-adobject “CN=ExServer2,CN=Autodiscover,CN=Protocols,CN=ExServer2,CN=Servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),CN=Administrative Groups,CN=Enterprise Exchange,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domain,DC=com” -Properties * | Select CN, objectclass, ServiceBindingInformation
Sleep 10

Sleeping 10 Sec

}While($C -ne 1002)

Windows Security – Select a Certificate window opens when connecting to an Exchange IIS Virtual Directory

Scenario: You notice that when you attempt to connect to a Exchange Servers virtual directory, such as https://<my_exchange_namespace>/autodiscover/autodiscover.xml ,
you receive a prompt similar to this:

Select a Certificate
Site <domain name or server name> needs your credentials>
<Certificates listed to select>

In our case, Autodiscover was not working correctly via DNS lookups, but the SCP record was pulling settings just fine.

Cause: Check the SSL Settings on the Virtual Directory in the Internet Information Services (IIS) Manager. Example: Expand Server –> Sites –> Default Web Site –> select Autodiscover (or whatever the virtual directory giving you an issue is). In the IIS area, select SSL Settings and make sure your certificate is setup to Ignore. You may want to go a hierarchical level higher and make sure the SSL settings are set correctly on the Default Web Site.

Timeout and Errors when running ‘Get-Mailbox -resultsize Unlimited’ within Exchange Online?

Scearnio: With a large number of mailboxes in our Exchange Online environment, anytime we run a command where it is get-mailbox -resultsize unlmited, we also run into errors/timeouts due to the amount of time and size it takes.

WorkAround: Use filtering within the get-mailbox command to split the data pull and join them into a Master Variable:

Create Variables

$All = @()
$d = (Get-date).adddays(-730)

Set Filter and Run

$f = “{WhenMailboxCreated -ge ‘$d’}”
$1 = get-recipient -filter $f -resultsize unlimited | select name, windowsliveid,primarysmtpaddress

Change Filter and Run

$f = “{WhenMailboxCreated -lt ‘$d’}”
$2 = get-recipient -filter $f -resultsize unlimited| select name, windowsliveid,primarysmtpaddress

Build the Master Variable to contain both datasets

$All += $1
$All += $2

Selecting specific rows from a CSV file to perform Powershell functions/commands against

Scenario: You have a large CSV file that you need to import and perform specific PowerShell commands against. You need the results in a hurry and you want to split up the CSV so you can run multiple PowerShell sessions at once to pull the results in parallel. Instead of creating separate CSV files to import for each PowerShell session, you can tell PowerShell which rows of the import you want to target.

Code Example:   In each PowerShell you can import the CSV file. When calling the variable for the loop you can specify the rows you want to target.  In this example we are going to set customattribute1 to the string “MigrateME” for the first 1000 (well 1001) entries in the csv file in one PowerShell session.  In a second PowerShell session I would import the code but change [0..1000] to [1001..2000],  and repeat the increment for each additional PowerShell session.

$users = Import-csv C:TempAll_Mailboxes.csv

$users[0..1000] | Select -expandproperty alias | %{ set-mailbox $_ -customattribute1 “MigrateMe”}