Entra / Microsoft 365 · Exchange Online
Update domain blocks
Reads domain block instructions from a SharePoint list and applies tenant allow/block lists plus Exchange transport rules.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -Scopes Sites.Read.All, Sites.Manage.All, Mail.Send -NoWelcomeConnect-ExchangeOnline -SkipLoadingCmdletHelp
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $SiteSearch = "Office 365 Adoption")Function Add-MessageRecipients {# Function to build an addressee list to send email[cmdletbinding()]Param([array]$ListOfAddresses )ForEach ($SMTPAddress in $ListOfAddresses) {@{ emailAddress = @{address = $SMTPAddress}}}}# Connect to the Graph SDK endpoint (tested with SDK V2.10)Connect-MgGraph -Scopes Sites.Read.All, Sites.Manage.All, Mail.Send -NoWelcome# To run in Azure Automation with a managed identity use# Connect-MgGraph -NoWelcome -IdentityConnect-ExchangeOnline -SkipLoadingCmdletHelp# to run in Azure Automation# $ServiceDomain = (Get-MgOrganization).VerifiedDomains | Where-Object {$_.IsInitial -eq $True} | Select-Object -ExpandProperty Name# Connect-ExchangeOnline -ManagedIdentity -TenantName $ServiceDomain -SkipLoadingCmdletHelp# Transport rules to use for blocking top-level domains (TLDs) and individual domains$TransportRuleName = "Block Inbound messages from selected top-level domains"$TransportRuleName2 = "Block Email From Selected Domains"$ExpirationDate = (Get-Date).AddDays(90).ToUniversalTime()# Recipient for the email sent at the end of the script - define the addresses you want to use here$EmailRecipient = "Peter.Bedson@o365maestro.onmicrosoft.com"# Message will be sent from the account running the script. If used with the Mail.Send permission in an Azure# Automation runbook, the sender can be any mailbox in the organization$MsgFrom = (Get-MgContext).Account$NewRuleCreated = $false; $NewRuleCreated2 = $false# SharePoint Site that stores the list holding data about blocks to apply$Site = Get-MgSite -Search $SiteSearch | Select-Object -First 1# List in the site with the block information$List = Get-MgSiteList -SiteId $Site.Id -Filter "displayName eq 'Domain Blocks'"# Read items from the list and build a PowerShell list object containing blocks to applyWrite-Output ("Fetching information about tenant blocks from SharePoint Online list {0}" -f $List.displayName)[array]$Data = Get-MgSiteListItem -ListId $List.Id -SiteId $Site.Id -ExpandProperty Fields[array]$Items = $Data.Fields.additionalProperties$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($Item in $Items) {$ItemtoBlock = $Item.Title$BlockType = $Item.DomainType$Notes = $Item.Value$DataLine = [PSCustomObject][Ordered]@{ItemToBlock = $ItemtoBlockBlockType = $BlockTypeNotes = $Notes}$Report.Add($DataLine)}# Now process the blocks in the listWrite-Output "Processing block instructions"# List to capture details of what the script does$BlockReport = [System.Collections.Generic.List[Object]]::new()# Create arrays for the two kinds of block processed by the script[array]$SenderBlocks = $Report | Where-Object {$_.BlockType -eq "Sender"} | Sort-Object ItemToBlock[array]$URLBlocks = $Report | Where-Object {$_.BlockType -eq "URL"} | Sort-Object ItemToBlock# Fetch the current set of blocks for each type[array]$CurrentSenderBlocks = Get-TenantAllowBlockListItems -ListType Sender | Select-Object Identity, Value[array]$CurrentURLBlocks = Get-TenantAllowBlockListItems -ListType URL | Select-Object -ExpandProperty Value# array to hold the TLDs to block with the transport rule[array]$TLDBlocksforTransportRule = $Null[array]$IndividualDomainBlocks = $Null# Process sender blocksForEach ($BlockSender in $SenderBlocks) {Write-Output ("Processing block for {0}" -f $BlockSender.ItemToBlock)# Check if a block already exists for this sender. If so, remove it$CheckSender = $CurrentSenderBlocks | Where-Object {$_.Value -eq $BlockSender.ItemToBlock}If ($CheckSender) {Write-Output ("Removing current block for {0}" -f $BlockSender.ItemToBlock)$Status = Remove-TenantAllowBlockListItems -ListType Sender -Ids $CheckSender.Identity -ErrorAction SilentlyContinue}# Add the new sender block list entry$Status = (New-TenantAllowBlockListItems -ListType Sender -Entries $BlockSender.ItemToBlock -Block `-ExpirationDate $ExpirationDate -ErrorAction SilentlyContinue)If ($Status) {Write-Output ("Block successfully applied for {0}" -f $BlockSender.ItemToBlock)$BlockData = [PSCustomObject][Ordered]@{Timestamp = Get-Date -Format sBlock = $BlockSender.ItemToBlockBlockType = 'Sender'}$BlockReport.Add($BlockData)} Else {Write-Output "Error occurred adding block"}}# Process URL blocksForEach ($BlockURL in $URLBlocks) {Write-Output ("Processing block for {0}" -f $BlockURL.ItemToBlock)If (($BlockURL.ItemToBlock.Substring(0,1)) -eq ".") {$URLToBlock = ("*{0}/*" -f $BlockURL.ItemToBlock)$TLDBlock = ("\{0}$" -f $BlockURL.ItemToBlock)$TLDBlocksforTransportRule += $TLDBlock} Else {$URLToBlock = $BlockURL.ItemToBlock$IndividualDomainBlocks += $BlockURL.ItemToBlock}# If URL is already blocked, remove the current blockIf ($URLToBlock -in $CurrentURLBlocks) {Write-Output ("Removing current block for {0}" -f $URLToBlock)$Status = Remove-TenantAllowBlockListItems -ListType URL -Entries $URLToBlock -ErrorAction SilentlyContinue}# Add the block for 90 days$Status = (New-TenantAllowBlockListItems -ListType URL -Entries $URLToBlock -Block `-ExpirationDate $ExpirationDate -ErrorAction SilentlyContinue)If ($Status) {Write-Output ("Block successfully applied for {0}" -f $URLToBlock)$BlockData = [PSCustomObject][Ordered]@{Timestamp = Get-Date -Format sBlock = $URLToBlockBlockType = 'URL'}$BlockReport.Add($BlockData)} Else {Write-Output "Error occurred adding block"}}If ($TLDBlocksforTransportRule) {# Now to update the transport rule to block TLDs if any TLDs are to be blocked.# First, check if a rule exists. If it doesn't, create it[array]$CheckTransportRule = Get-TransportRule -Identity $TransportRuleName -ErrorAction SilentlyContinue$Comments = ("Rule updated automatically on {0} to process TLDs: {1}" -f (Get-Date -format 'dd-MMM-yy HH:mm'), ($TLDBlocksforTransportRule -join ", "))If (!($CheckTransportRule)) {# Transport rule not present, so create new rule$NewRule = New-TransportRule -Name $TransportRuleName -Enabled $True `-FromAddressMatchesPatterns $TLDBlocksforTransportRule -SenderAddressLocation 'Header' `-Comments $Comments -Quarantine $trueIf ($NewRule) {Write-Output "Transport rule created to block email from specified TLDs"$NewRuleCreated = $true}} Else {# We have a transport rule, so update itWrite-Output "Updating transport rule for TLD blocks..."Set-TransportRule -Identity $TransportRuleName -FromAddressMatchesPatterns $TLDBlocksforTransportRule `-ErrorAction SilentlyContinue -Comments $Comments$BlockedTLDs = Get-TransportRule -Identity $TransportRuleName | Select-Object -ExpandProperty FromAddressMatchesPatternsIf (!(Compare-Object -ReferenceObject $TLDBlocksForTransportRule -DifferenceObject $BlockedTLDs)) {Write-Output ("Transport rule updated to block email from these TLDs {0}:" -f ($TLDBlocksforTransportRule -join ", "))}}}# And check if we have to block individual domainsIf ($IndividualDomainBlocks) {[array]$CheckTransportRule = Get-TransportRule -Identity $TransportRuleName2 -ErrorAction SilentlyContinue$Comments = ("Rule updated automatically on {0} to process domains: {1}" -f (Get-Date -format 'dd-MMM-yy HH:mm'), ($IndividualDomainBlocks -join ", "))If (!($CheckTransportRule)) {# Transport rule not present, so create new rule$NewRule = New-TransportRule -Name $TransportRuleName2 -Enabled $True `-SenderDomainIs $IndividualDomainBlocks `-Comments $Comments -Quarantine $trueIf ($NewRule) {Write-Output "Transport rule created to block email for individual domains"$NewRuleCreated2 = $true}} Else {# We have a transport rule, so update itWrite-Output "Updating transport rule to block specific email domains..."Set-TransportRule -Identity $TransportRuleName2 -SenderDomainIs $IndividualDomainBlocks -Comments $Comments `-ErrorAction SilentlyContinue$BlockedDomains = Get-TransportRule -Identity $TransportRuleName2 | Select-Object -ExpandProperty SenderDomainIsIf (!(Compare-Object -ReferenceObject $IndividualDomainBlocks -DifferenceObject $BlockedDomains)) {Write-Output ("Transport rule updated to block email from these domains: {0}" -f ($IndividualDomainBlocks -join ", "))}}}$ToRecipientList = @( $EmailRecipient )[array]$MsgToRecipients = Add-MessageRecipients -ListOfAddresses $ToRecipientList$MsgSubject = "Tenant blocks for email"$HtmlHead = "<h2>Updates to tenant block list</h2><p>The following tenant blocks have been applied.</p>"$HtmlBody = $BlockReport | ConvertTo-Html -Fragment$HtmlMsg = "</body></html><p>" + $HtmlHead + $Htmlbody + "<p>"If ($NewRuleCreated) {$HtmlMsg = $HtmlMsg + ("<p><b>New transport rule created to block top-level domains: {0}</b></p>" -f $TransportRuleName)} Else {$HtmlMsg = $HtmlMsg + ("<p>Transport rule <b>{0}</b> updated to block top-level domains</p>" -f $TransportRuleName)}If ($NewRuleCreated2) {$HtmlMsg = $HtmlMsg + ("<p><b>New transport rule created to block email from specific domains: {0}</b></p>" -f $TransportRuleName2)} Else {$HtmlMsg = $HtmlMsg + ("<p>Transport rule <b>{0}</b> updated to block email from specific domains</p>" -f $TransportRuleName2)}# Construct the message body$MsgBody = @{Content = "$($HtmlMsg)"ContentType = 'html'}$Message = @{subject = $MsgSubject}$Message += @{toRecipients = $MsgToRecipients}$Message += @{body = $MsgBody}$Params = @{'message' = $Message}$Params += @{'saveToSentItems' = $True}$Params += @{'isDeliveryReceiptRequested' = $True}# And send the message using the parameters that we've filled inSend-MgUserMail -UserId $MsgFrom -BodyParameter $ParamsWrite-Output ("Message containing update about tenant blocks sent to {0}!" -f $EmailRecipient)
Parameters
ParameterDefaultNotes
-SiteSearchOffice 365 AdoptionSharePoint site search term used to locate the organizational contacts list.Attribution
Author
Office365itpros