Scenario: You need a scriptlet that will search for all messages in Exchange Online looking for a specific sending email address pattern. Specifically I am looking for any email sent by any impersonating email address that looks like this: Steve.Contoso.com@gmail.com. I want to filter on the “.com@” pattern.
Scriptlet: Edit the “Configure these Variables” section and copy and paste the remainder of the script below.
#Look for the text pattern “.com@” as the sending addresses
#Configure these Variables
$filter = “.com@”
$start = “1/11/2021 00:00”
$end = “1/11/2021 23:59”
$pageSize = 1000
$P = 1
$messages = @()
$report = @()
$totalRecipients = 0
#End_Configure these Variables#######
#The Loop – no need to edit anything below
#Create Starting Loop Variables
$Loop_start = get-date($start) -format “MM/dd/yyyy HH:00:00”
$Loop_end = get-date($end) -format “MM/dd/yyyy HH:00:00”
$1Hour_end = get-date($Loop_start)
$1Hour_end = $1Hour_end.AddHours(1)
$1Hour_end = get-date($1Hour_end) -format “MM/dd/yyyy HH:00:00”
#Loop through All Messages
do
{
Do{
Write-Host “Message Trace $Loop_Start : $1Hour_end – Page $P…”
$temp_Messages = Get-MessageTrace -startdate $loop_Start -enddate $1Hour_End -PageSize $pagesize -Page $P
$filtered_messages = $temp_messages | Where SenderAddress -like “$filter“
$P++
$Messages += $filtered_Messages
}until ($temp_Messages -eq $null)
#recreate new variables
$P = 1
$Loop_Start = $1hour_end
$1Hour_end = get-date($Loop_start)
$1Hour_end = $1Hour_end.AddHours(1)
$1Hour_end = get-date($1Hour_end) -format “MM/dd/yyyy HH:00:00”
}While((get-date($Loop_start)) -lt (Get-date($Loop_End)))
#View the Results
$Messages
Category: Powershell
Clutter Settings are not available to a Exchange Online Mailbox
Scenario: A user wants to get rid of the Clutter functionality for their Mailbox, but does not see the Clutter settings within their Outlook client or Outlook on the Web (aka OWA or whichever name you want to refer to it as since its been rebranded so many times). Typically there are clutter options available to the end user within their client. However Clutter settings will only appear when:
If user currently has Clutter enabled:
-Clutter settings appear
If user currently has Focused Inbox enabled:
-Clutter settings will not appear
If neither Clutter or Focused Inbox is enabled:
-Both Clutter and Focused Inbox appear as options in the user’s Mail Settings
Solution: If disabling the Focused Inbox doesnt allow it to appear, feel free to disable Clutter from the backend by running commands similar to this:
set-clutter -identity steve -enable $False (Or $true to turn it back on)
get-clutter -identity steve | Select IsEnabled
Dumpster of Exchange Online Mailboxes that are on a Hold are maxed out due to bloated recurring meetings
Scenario: We noticed that a handful of mailboxes that are on a hold had their dumpsters maxed out hitting their 110GB RecoverableItemsQuota. The RecoverableItemsQuota increased from 100GB to 110GB when we enabled the AutoExpandingArchiveEnabled property. The users were experiencing these symptoms:
– Users cannot delete items from the Deleted Items folder
-ManagedFolderAssistant may have been hanging on large items, preventing smaller items from moving into the archive via our retention policies
-Users cannot managed or accept updated meeting requests
-Weird intermittent sending/bounceback issues for each user.
Investigating: We discovered a bloated recurring calendar item stored in the Versions folder (Recoverable Items/Dumpster folder). These mailboxes have archive mailboxes as well as retention policies, but it seemed if the retention policy was not moving the items out of the Versions folder into the Archive Versions folder. What also stuck out was there were only 400-500 items in the Versions folder, yet the total size of the Versions folder was near the 100GB mark. We found this by running a command similar to: get-mailboxfolderstatistics steve | Select Name, ItemsinFolder,FolderSize
We also used MFCMAPI to enter into the mailbox to view the contents of the Versions folder. Of the hundreds of items listed in the Versions folder, it was all the same meeting (just a different version of it) and the size of each item ranged from 200MB to 300MB a piece. This means that native Exchange functionality such as Retention Policies would not move the email items into the archive mailbox because they exceeded the MaxSendSize and MaxReceiveSize.
Further investigation, we asked the meeting owner how they were managing the meeting. The meeting owner would manage each occurrence of the meeting separately by updating it with a daily agenda and attachments. This meeting happens every day, meaning it did not take too long for this recurring meeting to bloat past the size that Microsoft can handle.
The Fix: The Holds placed on the mailbox put us into a bind, because at the time there wasn’t an easy way of getting rid of these items by simply deleting them via a Search And Destroy Script, MFCMAPI, or Native Exchange Retention Policies. However it was discovered that we could run this one-liner which was able to remove all of the excess versions for the recurring meeting:
Start-ManagedFolderAssistant steve -HoldCleanup
In prep for the fix, we made sure we put all the items in the versions folder because we were moving them around experimenting. Then ran the command. A few of the users made immediate progress, while others didn’t budge. For those that didnt budge, we ran the -StopHoldCleanup switch and reissued the -HoldCleanup switch. Eventually within a few days, they were cleaned up too.
Determine when a user can start sending email again after hitting the 10,000 Recipient Rate Limit in Exchange Online
Scenario: Recently we had a user who hit the 10K Recipient Rate Limit in a 24 hour period within Exchange Online. This user was performing two types of emailing from their ExOnline mailbox: 1. Sending mass mailings from their Mailbox using their from address and 2. Sending mass mailings from their Mailbox and setting another From Address (Delegated Send-as Permissions for a Service Account). Both types of sending impacted the recipient rate limit for the persons mailbox.
BTW – Do not mass mail directly to recipients from an ExOnline mailbox. Instead use distribution groups or other third party mailing systems to send mass communications.
Scriptlet: Here is a scriptlet to help determine when the user should be able to send from their mailbox again. The results provide hourly recipient counts for the sender which may help in determine the timeframe when a user should no longer be impacted by the 24 hour period:
Edit the Variables in the scriptlet and paste it into Exchange Online PowerShell.
#Edit these variables
$sender= “SteveTheMassMailer@domain.com”
$start = “1/7/2021”
$end = “1/9/2021”
$pageSize = 1000
$P = 1
$messages = $null
$report = @()
$totalRecipients = 0
#Loop for All Messages
do
{
Write-Host “Message Trace – Page $P…”
$temp_Messages = Get-MessageTrace -senderaddress $sender -startdate $start -enddate $end -PageSize $pagesize -Page $P
$P++
$Messages += $temp_Messages
}until ($temp_Messages -eq $null)
#Display messages or Message Count
#$Messages
$Messages.count
#Build the Loop Parameters
$Loop_start = get-date($messages | Sort Received | Select -expandproperty Received -First 1) -format “MM/dd/yyyy HH:00:00”
$Loop_end = get-date($messages | Sort Received | Select -expandproperty Received -last 1) -format “MM/dd/yyyy HH:00:00”
$1Hour_end = get-date($Loop_start)
$1Hour_end = $1Hour_end.AddHours(1)
$1Hour_end = get-date($1Hour_end) -format “MM/dd/yyyy HH:00:00”
#Now Loop It!
“Starting Loop for $sender”
Do{
“Checking $Loop_Start and $1Hour_end”
$RecipientCount = $messages | Where {($_.Received -gt $loop_start) -and ($_.Received -lt $1hour_end)} | Select RecipientAddress
$totalrecipients = $totalRecipients + $recipientCount.count
$recipientCount = $RecipientCount.count
#Report it
$obj = New-Object PSObject
$obj | Add-Member NoteProperty -Name StartTime -Value $Loop_Start
$obj | Add-Member NoteProperty -Name EndTime -Value $1hour_End
$obj | Add-Member NoteProperty -Name RecipientCount -Value $RecipientCount
$Report += $obj
#New Variables
$Loop_Start = $1hour_end
$1Hour_end = get-date($Loop_start)
$1Hour_end = $1Hour_end.AddHours(1)
$1Hour_end = get-date($1Hour_end) -format “MM/dd/yyyy HH:00:00”
}While( (get-date($Loop_start)) -lt (Get-date($Loop_End)))
#Summary
$report
“#Summary######################################################”
“-Results are reported in GMT”
“- Total Recipient Count for $Sender between $start – $end : $TotalRecipients”
Microsoft Example of the 24 hour Recipient Rate Limit:
After the recipient rate limit is reached, messages can’t be sent from the mailbox until the number of recipients that were sent messages in the past 24 hours drops below the limit. For example, a user sends an email message to 5000 recipients at 09:00 AM, then sends another message to 2500 recipients at 10:00 AM, and then sends another message to 2500 recipients at 11:00 AM, hitting the limit of 10,000 messages. The user won’t be able to send messages again until 09:00 AM the next day.
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.
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
Delegate Permissions to an AD Organizational Unit via PowerShell
Scenario: You want to give Full Control delegate access to a AD Group to a specific AD Organizational Unit and its sub objects.
Scriptlet:
#Add Rights Indiviudally
$ou = "AD:\OU=New,DC=Domain,DC=Com"
$group = Get-ADGroup "Exchange Admins"
$sid = new-object System.Security.Principal.SecurityIdentifier $group.SID
$acl = get-acl $ou
$identity = [System.Security.Principal.IdentityReference] $SID
$adRights = [System.DirectoryServices.ActiveDirectoryRights] "GenericAll"
$type = [System.Security.AccessControl.AccessControlType] "Allow"
$inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance] "All"
$ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $identity,$adRights,$type,$inheritanceType
$ace = new-object System.DirectoryServices.ActiveDirectoryAccessRule $sid,"GenericAll","Allow","All"
$acl.AddAccessRule($ace)
set-acl -AclObject $acl $ou
Active Directory: Identify Delegated Permissions for AD Organizational Units
Scenario: You want to pull a report of all delegated permissions to AD Organizational Units.
Scriptlet:
$sourceOU = "OU=NEW,DC=Domain,DC=Com"
$OUs = Get-ADOrganizationalUnit -SearchBase $sourceOU -filter * | Select -ExpandProperty DistinguishedName | Sort {$_.length}
$output = "C:\temp\ace.csv"
$OUs | %{
$ou = "AD:\"+$_
"Checking $OU"
$acl = get-acl $ou
$ace = $acl.access | Where IsInherited -eq $false
$ace | Select @{Name="OU";Expression={"$ou"}},ActiveDirectoryRights, InheritanceType,ObjectType,InheritedObjectType,ObjectFlags,AccessControlType,IdentityReference,IsInherited,InheritanceFlags,PropagationFlags | Export-csv $output -append
}
Active Directory: Copy OU hierarchy from one OU to another OU
Scenario: You want to copy the Sub OU structure/hierarchy from one Parent OU to another Parent OU.
Scriptlet:
#Create OU's
#Import Module
import-module activedirectory
#Variables
$sourceOU = "OU=Old,DC=Domain,DC=com"
$destinationOU = "OU=New,DC=Domain,DC=com"
$adPath= "LDAP://" + $destinationOU
$objDomain=New-Object System.DirectoryServices.DirectoryEntry($adPath)
$ObjSearch=New-Object System.DirectoryServices.DirectorySearcher($ObjDomain)
[array] $OUs = @()
#Query for OUs and Exclude an OU if needed
$OUs = Get-ADOrganizationalUnit -SearchBase $sourceOU -filter * | Where Distinguishedname -notlike "Service" | Select -ExpandProperty DistinguishedName | Sort {$_.length}
#Loop to build the OU Structure
for ($k=0; $k -le $OUs.Count -1; $k++)
{
$OriginalOU = $OUs[$k]
$OriginalOU = "AD:\"+$OriginalOU
$OUtoCreate = ($OUs[$k] -replace $sourceOU,$destinationOU).ToString()
$OUSearch = ($OUtoCreate -replace '"',"").ToString()
$ObjSearch.Filter = "(&(objectCategory=organizationalUnit)(distinguishedName="+ $OUSearch + "))"
$allSearchResult = $ObjSearch.FindAll()
$FinalOU = "AD:\"+$OUtoCreate
if ($allSearchResult.Count -eq 1)
{
"No changes were done on = " + $OUtoCreate
}
else
{
dsadd ou $OUtoCreate
"OU Creation = " + $OUtoCreate
}
}
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