Your message wasn’t delivered to anyone because there are too many recipients.

Scenario: A user with a Exchange Online receives the following error: “Your message wasn’t delivered to anyone because there are too many recipients. The limit is 0. Your message has 1 recipients.

Investigation:

In Exchange Online, check the RecipientLimits on the mailbox: get-mailbox steveman | Select RecipientLimits

Fix: If not set correctly, run the following: set-mailbox -recipientlimits 500

———————————————————–

If Hybrid, also check the remote mailbox in Exchange On-Premises: get-remotemailbox steveman | Select RecipientLimits

Fix: If not set correctly, run the following (AD PowerShell):
Set-ADUser steveman -Replace @{msexchRecipLimit=”500″}

Note: There is no set-remotemailbox -recipientlimits, this is why you need to perform this using AD PowerShell

Perform an action only on the the first email in a email conversation

Scenario: You want to create an action, such as an alert, only when someone sends the first email in a email conversation/thread. However, you DO NOT want to perform that action when someone replies to the initial email.

Scriptlet: You can use an Exchange Transport Rule to detect the first email in a email conversation when the email initiated from within Exchange. Here is the Transport Rule code that will alert another recipient (specifically a page to my cell phone) when someone emails a specific email address. We will use Regex to detect the 32 character value in the Thread-Index header that ends with “==”, which identifies the first email in a conversation thread.

New-TransportRule -name “Perform_Action_On_First_Email” -Enabled $true -HeaderMatchesMessageHeader “Thread-Index” -HeaderMatchesPatterns “^.{30}==$” -RecipientAddressContainsWords servicedesk@domain.com -blindcopyto Page-Steves-Phone@domain.com

Exchange Online: Cached Mode or Online Mode from their Outlook Client

Scenario: Can we identify users that are using Cached Mode or Online Mode from their Outlook client when connecting to their Exchange Online Mailbox via Microsoft Online tools or reporting?

Answer: No – At least not as of today, 11/17/2020.

Microsoft Online currently does not provide this level of detail of connection data for Outlook MAPI connections. In Exchange On-Premises, you had this information stored in RPC logs that could be parsed through. In Exchange Online, we do not have the access.

In order to determine if Cached Mode is enabled for the Outlook client connections, you would need to perform logic on the client initiating the connection.

Exchange Online Restore and Recovery

Restore and Recovery Options for Exchange Online as of 11/16/2020:

Point-in-Time Restore: Not Available. Exchange Online is SaaS. There is no access to database or the log files in Exchange Online. 3rd Party solutions may produce experiences close to Point-in-Time restores, but its built on logic that uses EWS or other front end client access protocols, not necessarily connecting to the raw database and log files.

RetainDeletedItemsFor: 30 Days (max). When email items are hard-deleted from the mailbox, the items will be stored in the Deletions Recoverable Items folder where the items will be recoverable via OWA or Outlook using “Recover Deleted Items” functionality.

Holds:
Litigation Hold: When enabled, all items are protected and nothing will be purged from the mailbox
Compliance/InPlace Holds: When enabled, only items that match specific criteria will be protected and not purged from the mailbox.

SCC Retention Policy: Email can be protected for a certain period of time based on the Received date of the email item.

Lagged Copy for Logical Corruption: A passive database copy will be a lagged copy where it will delay processing log files for a certain time . In the event of logical database corruption, this passive database copy can be used to prevent further corruption to the local database copy

Soft-Deleted Mailbox or 3rd party restore in Exchange On-Premises (previous migrated/on-boarded to Exchange Online): If you recently migrated to Exchange Online, you may be able to access a soft-deleted version of the mailbox using Exchange On-Premises tools and any third party backup software that was used prior to the migration.

Single Item Recovery: Single Item Recovery is enabled by default in Exchange Online. If a user was to attempt to purge out of their “Recover Deleted Items” (Deletions Dumpster folder), than the message would still be retained for the “RetainDeletedItemsFor” period before it is purged.

Note: Folder structure is not recoverable, only email items.

ATP Safe Attachment Scanning Delay

Scenario: We noticed that messages were taking longer to deliver when ATP Safe Attachments was being called for message processing. Users in the Dynamic action policy noticed that the attachment would be reinserted hours after the message delivery. Other users in a Replace action policy noticed that the entire message was delayed delivery for hours.

Script: We found a script online that we modified to fit our needs. Here is our modified version of the script:

ATP Safe Attachment Scanning Delay Scriptlets


#Declare Variables
$Outfile = “C:\temp\ATPSafeAttachmentScan-$(Get-Date -Format “MMddyyyy_hhmmss”).csv”
$MessageList = $null 
$CurrMessages = $null
$Page = 1
$PageSize = 5000
$start = (Get-Date).AddHours(-4)
$end = Get-Date

$MessgaeListCount = 0


#Loop for Message Trace
do 
{   
Write-Host “Collecting Message Trace – Current Count: $MessageListCount – Page $Page…” 

$CurrMessages = Get-MessageTrace -StartDate $start -EndDate $end -PageSize $pagesize -Page $Page -Status Delivered | Where {$_.Size -gt 1MB}

$Page++ 
$MessageList += $CurrMessages 
$MessageListCount = $messageList.count
} until ($CurrMessages -eq $null)



#Loop Message Trace Results for ATP Events
$Row = 0
$TotalRow = $MessageList.count

$MessageList | Select-Object -Skip $Row | % {
    $ID = ($_.MessageTraceId).Guid
    $Sender = $_.SenderAddress
    $Recipient = $_.RecipientAddress
    $Size = $_.Size
    $MessageDetails = $_ | Get-MessageTraceDetail | where { $_.Event -eq “Advanced Threat Protection” -or $_.Event -eq “Deliver”} | sort Date
    $First = ($MessageDetails | select -First 1).Date
    $Last = ($MessageDetails | select -Last 1).Date


    # Only if ATP was used
    If ($First -ne $null -and $Last -ne $null) {
        If ($First -eq $Last) {$Delay = 0}
        Else { $Delay =  [math]::Round((New-TimeSpan –Start $First –End $Last).TotalSeconds,0) }
        $Item = New-Object System.Object;
        $Item | Add-Member -Type NoteProperty -Name “ID” -Value $ID;
       $Item | Add-Member -Type NoteProperty -Name “Sender” -Value $Sender;
        $Item | Add-Member -Type NoteProperty -Name “Recipient” -Value $Recipient;
        $Item | Add-Member -Type NoteProperty -Name “Size” -Value $Size;        $Item | Add-Member -Type NoteProperty -Name “Start” -Value $First;
        $Item | Add-Member -Type NoteProperty -Name “End” -Value $Last;
        $Item | Add-Member -Type NoteProperty -Name “Delay” -Value $Delay;
        #$results += $Item
        $Item | Export-Csv $Outfile  -NoTypeInformation -Append    }

    $Row++
    Write-Host “$(Get-Date -Format “HH:mm”): Processed row $Row out of $TotalRow” }
}






#REF: Original Script that we modified: https://jocha.se/blog/tech/exchange-atp-attachment-delay

Exchange Online: Place a hold on a Soft-Deleted mailbox

Scenario: Recently a user has left the organization and you need to place a hold on the Exchange Online mailbox. Currently the mailbox is SoftDeleted (get-mailbox -softdeletedmailbox).

Solution/Scriptlets:
If a Microsoft Security and Compliance case is not already configured, create a one via PowerShell of course! The scriptlets below will create the Compliance Case, Case Hold Policy, and the Case Hold Rule. The Case Hold Policy will group all specified mailboxes to be placed on Hold and the Case Hold Rule will set the entire mailbox on hold.

New-ComplianceCase “InactiveMailboxes_Hold” -Description “This is a hold for mailboxes that are no longer active”

New-CaseHoldPolicy -Case InactiveMailboxes_hold -Name InactiveMailboxes_Hold -ExchangeLocation Steve,Bob -Enabled $true


Note: If the mailboxes are Inactive/SoftDeleted, you may have to place a period in front of the name similar to this command: New-CaseHoldPolicy -Case InactiveMailboxes_hold -Name InactiveMailboxes_Hold -ExchangeLocation .Steve,.Bob -Enabled $true

New-CaseHoldRule -Name InactiveMailboxes_Hold -Policy InactiveMailboxes_hold


If the eDiscovery case is already created and you need to add users, run the following:

set-caseholdpolicy InactiveMailboxes_hold -AddExchangeLocation Jim

Complex Search criteria for New-ComplianceSearch -ContentMatchQuery

Scenario: You need to search the entire Exchange Online organization for emails with specific criteria:
-Received: 5/1/2020 — 5/15/2020
-Subject: “This is a test”
-Keywords: Trophy OR Lose OR Award

Scriptlets:

$name = “Search_11102020”

New-ComplianceSearch -Name $name -Description “This is a compliance search made from PowerShell” -ExchangeLocation ALL -ContentMatchQuery “Trophy (c:s) Lose(c:s) Award(c:c)(subject:’This is a test’)(received=2020-05-01..2020-05-15)”

Start-ComplianceSearch $name

Notes:
(c:c) = AND
(c:s) = OR


Put a hold on a Soft-Deleted Mailbox in Exchange Online

LEGACY: The instruction below with the steps to create a Mailbox Search is no longer relevant and has been deprecated by Microsoft. Go to this post for an updated version on how to perform this via the Microsoft Security and Compliance Center:
https://ex-shell.com/2020/11/11/exchange-online-place-a-hold-on-a-soft-deleted-mailbox/

Scenario: A person is no longer with the organization and their mailbox is currently retained in Exchange Online as a Soft-Deleted mailbox (get-mailbox -softdeletedmailbox). It was discovered that we need to place the mailbox on a hold to keep the email data preserved.

Scriptlets:
We are going to create a InPlace Hold on the inactive mailbox by running the following commands:

$mbx = get-mailbox -identity <user> -softdeletedmailbox

New-MailboxSearch -Name “InactiveMailboxHold” -SourceMailboxes $mbx.DistinguishedName -InPlaceHoldEnabled $true



Run Get-ADUser by pulling the WindowsLiveID from the Exchange Online Mailbox

Scenario: You need to pull in additional AD properties for users with Exchange Online mailboxes that are only available when running the Get-ADUser command because they are not included in the AD Sync to Microsoft Online/Azure.

Scriptlet:

Declare Variables:

$mbx = Get-mailbox -resultsize unlimited

$ADUserData = @()

$c=0 #Just for a counter

Run the Loop:

$mbx | Where WindowsLiveID -ne “” | Sort | %{

$c++ #Increase the Counter

$upn = $_.windowsliveid #Create the UPN based off windowsliveid

$f = “Userprincipalname -eq ‘$upn'” #Create a Filter for get-aduser

“$c – $f ” #Display on PS Screen

$ADuserData += get-aduser -filter $f -properties * #Fill in $userData with Get-Aduser Data

}

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