How To Warn users for Email Impersonation Phishing mail

Phishing emails are a constant threat to your IT environment. Besides all the security measures that you can take, is the awareness of your users really important. You can help them by warning them of potential phishing emails.

I have written before about how you can add a warning to phishing emails based on suspicious words in the subject or content. But another common tacking from attackers is to use impersonation.

add warning to email with same display name

They pretend to send the email as someone from inside your organization, using a display name that matches one of your users’ names.

You can help your users detecting these kinds of phishing emails by adding a warning to external emails that have a matching display name.

Creating a Transport Rule to add a warning when display name exists Internally with PowerShell

To add a warning to emails we will need to create a transport rule in Exchange Online. We also need a list with all the display names from our organization. Both can be done with PowerShell.

For the warning message, we are going to use the same layout as we have used for the phishing email warning. If you want to know more about it, or how to change the look, make sure you read this article.

As always, I will first explain how the script is build up and at the end of the article you can find the complete script.

Get all Display Names with Exchange Online

The first step is to get all the display names from your organization. To keep the script simple, we are going to use Exchange Online for this. You will need to choose if you want to add the names of the shared email boxes as well.

Make sure you are connected to Exchange Online. If you want all mailboxes (inc shared) then remove -RecipientTypeDetails usermailbox from the command below.

# Get all existing users
$displayNames = (Get-EXOMailbox -ResultSize unlimited  -RecipientTypeDetails usermailbox).displayname

Get Existing Transport rule

Users come and go in your organization, so we need to be able to update the list with display names. So we set our transport rule name and then check if the rule already exists later on.

# Set the transport rule name
$transportRuleName = "Impersonation warning"

# Get existing transport rule
$existingTransportRule =  Get-TransportRule | Where-Object {$_.Name -eq $transportRuleName}

Create the Warning Banner

We also need to define the warning banner which we are going to add to the emails:

$HTMLDisclaimer = '<table border=0 cellspacing=0 cellpadding=0 align="left" width="100%">
	<tr>
		<td style="background:#ffb900;padding:5pt 2pt 5pt 2pt"></td>
		<td width="100%" cellpadding="7px 6px 7px 15px" style="background:#fff8e5;padding:5pt 4pt 5pt 12pt;word-wrap:break-word">
			<div style="color:#222222;">
				<span style="color:#222; font-weight:bold;">Warning:</span>
				This email was sent from outside the company and it has the same display name as someone inside our organisation. This is probably a phishing mail. Do not click on links or open attachments
				unless you are certain that this email is safe.
			</div>
		</td>
	</tr>
</table>
<br/>'

Create the Transport Rule with PowerShell

With all the components in place, we can add the transport rule with PowerShell. The rule will be applied to all emails sent from outside the organization, where the From field matches one of the display names.

	Write-Host "Creating Transport Rule" -ForegroundColor Cyan

	# Create new Transport Rule
	New-TransportRule -Name $transportRuleName `
										-FromScope NotInOrganization `
										-SentToScope InOrganization `
										-HeaderMatchesMessageHeader From `
										-HeaderMatchesPatterns $displayNames `
										-ApplyHtmlDisclaimerLocation Prepend `
										-ApplyHtmlDisclaimerText $HTMLDisclaimer `
										-ApplyHtmlDisclaimerFallbackAction Wrap

	Write-Host "Transport rule created" -ForegroundColor Green

The complete script

Putting it all together results in the script below. You can also download it from my Github repo.

# Connect to Exchange Online
Write-Host "Connect to Exchange Online" -ForegroundColor Cyan
Connect-ExchangeOnline

$HTMLDisclaimer = '<table border=0 cellspacing=0 cellpadding=0 align="left" width="100%">
	<tr>
		<td style="background:#ffb900;padding:5pt 2pt 5pt 2pt"></td>
		<td width="100%" cellpadding="7px 6px 7px 15px" style="background:#fff8e5;padding:5pt 4pt 5pt 12pt;word-wrap:break-word">
			<div style="color:#222222;">
				<span style="color:#222; font-weight:bold;">Warning:</span>
				This email was sent from outside the company and it has the same display name as someone inside our organisation. This is probably a phishing mail. Do not click on links or open attachments
				unless you are certain that this email is safe.
			</div>
		</td>
	</tr>
</table>
<br/>'

# Get all existing users
$displayNames = (Get-EXOMailbox -ResultSize unlimited  -RecipientTypeDetails usermailbox).displayname

# Set the transport rule name
$transportRuleName = "Impersonation warning"

# Get existing transport rule
$existingTransportRule =  Get-TransportRule | Where-Object {$_.Name -eq $transportRuleName}

if ($existingTransportRule) 
{
	Write-Host "Update Transport Rule" -ForegroundColor Cyan

	# Update existing Transport Rule
	Set-TransportRule -Identity $transportRuleName `
										-FromScope NotInOrganization `
										-SentToScope InOrganization `
										-HeaderMatchesMessageHeader From `
										-HeaderMatchesPatterns $displayNames `
										-ApplyHtmlDisclaimerLocation Prepend `
										-ApplyHtmlDisclaimerText $HTMLDisclaimer `
										-ApplyHtmlDisclaimerFallbackAction Wrap

	Write-Host "Transport rule updated" -ForegroundColor Green
}
else 
{
	Write-Host "Creating Transport Rule" -ForegroundColor Cyan

	# Create new Transport Rule
	New-TransportRule -Name $transportRuleName `
										-FromScope NotInOrganization `
										-SentToScope InOrganization `
										-HeaderMatchesMessageHeader From `
										-HeaderMatchesPatterns $displayNames `
										-ApplyHtmlDisclaimerLocation Prepend `
										-ApplyHtmlDisclaimerText $HTMLDisclaimer `
										-ApplyHtmlDisclaimerFallbackAction Wrap

	Write-Host "Transport rule created" -ForegroundColor Green
}

# Close Exchange Online Connection
$close = Read-Host Close Exchange Online connection? [Y] Yes [N] No 

if ($close -match "[yY]") {
  Disconnect-ExchangeOnline -Confirm:$false | Out-Null
}

Transport Rule in Exchange Online

You can find the transport rule in Exchange Online after you have executed the script:

  1. Open the Exchange Admin Center
  2. Expand Mail flow and select Rules
  3. Open the rule Impersonation Warning to see the details
create exchange online transport rule with PowerShell

Wrapping Up

If you are adding the names of shared mailboxes to the list as well, then you probably want to filter out names like “info” from the list, because info is pretty common 😉

The size of a transport rule is limited, so when you have a large tenant, with more than 250 users, you might need to create multiple transport rules.

If you have any questions, just drop a comment below.

Get more stuff like this

IT, Office365, Smart Home, PowerShell and Blogging Tips

I hate spam to, so you can unsubscribe at any time.

25 thoughts on “How To Warn users for Email Impersonation Phishing mail”

  1. Hey Frank,

    Thanks for posting updated code.

    I have updated my script but its returning back with the below.

    Creating Impersonation Transport Rule 1 …
    Write-ErrorMessage : |System.InvalidOperationException|The rule can’t be created because it is too large. It has 10623 characters,
    and the maximum number of characters is 8192. Reduce the size, either by removing content, such as words or regular expressions,

  2. Hello,

    I have a question about the warning banner. Will the banner still remain in the mail conversation when I press reply on an external email?

  3. Thank you for this! I have copied and it is working. However, I have one issue. The background highlight doesn’t work all the time. I have tested sending mail to my company email using my gmail and icloud ID. On gmail, it works perfectly but on my icloud mail it gets the disclaimer message but no backgroud color/highlight. Please advise. Thank you

  4. I modified the loop for breaking into multiple transports and tested it.

    Replace the section after else.

    {
    $chunks = [System.Collections.ArrayList]::new()
    for ($i = 0; $i -lt $displayNames.Count; $i += 100) {
    if (($displayNames.Count – $i) -gt 99 ) {
    $chunks.add($displayNames[$i..($i + 99)])
    }
    else {
    $chunks.add($displayNames[$i..($displayNames.Count – 1)])
    }
    }

    $c = 0;
    foreach ($chunk in $chunks) {
    Write-Host “Creating Transport Rule” -ForegroundColor Cyan

    # Create new Transport Rule
    New-TransportRule -Name “$transportRuleName-$C” `
    -FromScope NotInOrganization `
    -SentToScope InOrganization `
    -HeaderMatchesMessageHeader From `
    -HeaderMatchesPatterns $chunk `
    -ApplyHtmlDisclaimerLocation Prepend `
    -ApplyHtmlDisclaimerText $HTMLDisclaimer `
    -ApplyHtmlDisclaimerFallbackAction Wrap

    Write-Host “Transport rule $c created” -ForegroundColor Green
    $c = $c + 1
    }
    }

    • Hello, Amazing script, thanks.

      But there is a little issue with the loop. When i try to restart the script, the update part is not working.
      I’m not a Powershell master user but if i’m understand correctly, the script try to find a rule name “Impersonation warning” but in the loop section change the name for “Impersonation warning-0, -1, -2 …) so the update part of the script can’t find them.

      So for now i’m deleting the 4 rules created by the script and replay it.

      it will be very nice if you can adjust it for a newbie like me 🙂

      But still it is a fantastic script, so thank you for that.

      • Helene, I quickly added this script to do the following:
        1. Export all rules (in case things go wrong) to a file name that will include a Date and Time
        2. Delete all rules that contain “impersonation” in their name

        This is my quick-win script as I couldn’t get the script to update as I’m also not an expert in PowerShell

        #export/backup ALL rules
        $file = Export-TransportRuleCollection
        [System.IO.File]::WriteAllBytes(“I:\temp\Exchange Rules $(((get-date).ToUniversalTime()).ToString(“yyyy-MM-dd_HH-mm”)).xml”, $file.FileData)

        #list all “impersonation” only rules and store them in a variable, then delete all
        $tRules = Get-TransportRule | Where-Object {$_.Name -match ‘Impersonation’}
        $int = 0;
        foreach ($tRule in $tRules) {
        #Start-Sleep -s 2
        Remove-TransportRule -identity “$tRule” -Confirm:$false
        Write-host “$tRule not/deleted…” -ForegroundColor Red
        $int = $int +1
        }

  5. This is awesome. Many thanks for the hard work. One question though. What happens when a display name is changed or a new user is added? I assume you would have to run the script to update the rule. I am just thinking if a member of my Team performs the display name change/add a new user without letting me know so I can perform the follow-up action.

  6. Hi
    Have copied your script only translated it to swedish, but i keep getting error message
    The rule can’t be created because it is too large. It has 24183 characters, and the maximum number of characters is 8192. Reduce the
    size, either by removing content, such as words or regular expressions, from the rule; or by removing conditions, exceptions, or
    actions from the rule.
    How do you get it to work?
    Whitout it geeting to large

        • I think you will have to break up the list into smaller batches, creating multiple exchange rules.

          Something like this:


          $chunks = [System.Collections.ArrayList]::new()
          for ($i = 0; $i -lt $displayNames.Count; $i += 100) {
          if (($displayNames.Count - $i) -gt 99 ) {
          $chunks.add($displayNames[$i..($i + 99)])
          }
          else {
          $chunks.add($displayNames[$i..($displayNames.Count - 1)])
          }
          }

          $c = 0;
          foreach ($chunk in $chunks) {
          Write-Host "Creating Transport Rule" -ForegroundColor Cyan

          # Create new Transport Rule
          New-TransportRule -Name "$transportRuleName-$C" `
          -FromScope NotInOrganization `
          -SentToScope InOrganization `
          -HeaderMatchesMessageHeader From `
          -HeaderMatchesPatterns $chunks `
          -ApplyHtmlDisclaimerLocation Prepend `
          -ApplyHtmlDisclaimerText $HTMLDisclaimer `
          -ApplyHtmlDisclaimerFallbackAction Wrap

          Write-Host "Transport rule $c created" -ForegroundColor Green
          }

          I haven’t tested it

          • It wasn’t updating correctly, I made some adjustments

            # Get all existing users
            $displayNames = (Get-EXOMailbox -ResultSize unlimited -RecipientTypeDetails usermailbox).displayname

            # Set the transport rule name
            $transportRuleName = “Impersonation warning”

            $chunks = [System.Collections.ArrayList]::new()
            for ($i = 0; $i -lt $displayNames.Count; $i += 100) {
            if (($displayNames.Count – $i) -gt 99 ) {
            $chunks.add($displayNames[$i..($i + 99)])
            }
            else {
            $chunks.add($displayNames[$i..($displayNames.Count – 1)])
            }
            }

            Write-Host “Started looping displayNames chunks …” -ForegroundColor Cyan
            $c = 1;
            foreach ($chunk in $chunks) {

            # Get existing transport rule
            $existingTransportRule = Get-TransportRule | Where-Object {$_.Name -eq “$transportRuleName $c”}

            if ($existingTransportRule)
            {
            Write-Host “Updating Transport Rule $c …” -ForegroundColor Cyan

            # Update existing Transport Rule
            Set-TransportRule -Identity “$transportRuleName $c” `
            -FromScope NotInOrganization `
            -SentToScope InOrganization `
            -HeaderMatchesMessageHeader From `
            -HeaderMatchesPatterns $displayNames `
            -ApplyHtmlDisclaimerLocation Prepend `
            -ApplyHtmlDisclaimerText $HTMLDisclaimer `
            -ApplyHtmlDisclaimerFallbackAction Wrap

            Write-Host “Transport rule $c updated.” -ForegroundColor Green
            }
            else
            {
            Write-Host “Creating Transport Rule $c …” -ForegroundColor Cyan

            # Create new Transport Rule
            New-TransportRule -Name “$transportRuleName $c” `
            -FromScope NotInOrganization `
            -SentToScope InOrganization `
            -HeaderMatchesMessageHeader From `
            -HeaderMatchesPatterns $displayNames `
            -ApplyHtmlDisclaimerLocation Prepend `
            -ApplyHtmlDisclaimerText $HTMLDisclaimer `
            -ApplyHtmlDisclaimerFallbackAction Wrap

            Write-Host “Transport rule $c created.” -ForegroundColor Green
            }
            $c++
            }

            Write-Host “Finished looping displayNames chunks.” -ForegroundColor Cyan

  7. Woo hoo! Thank you so much. This is now working! I’m going to keep following you to see what else I can learn. Thanks again!

  8. Ok, I do have that option! It wasn’t available to me because I had used 2 conditions to apply the rule already – apply the rule if the sender is located outside the organization and the recipient is located inside the organization. If I get rid of that second condition which really isn’t needed, I see where I can choose Header. Thank you!

  9. Unfortunately, I’m lost on this part. I don’t have the option to change the sender’s specified properties to Header. I’m using the rules on the Exchange admin center and only have certain options I can pick from. Under the sender’s specified properties match these text patterns, I can select user properties, and DisplayName is one of them but there’s nothing about header.

    I think you’re using a program that perhaps I don’t have?

  10. Is it possible to create this rule in the exchange admin center, rather than use Power Shell? We often get random email addresses using only certain names as Display Names.

    I created a warning within the rules, just like I did for external emails (following one of your articles, and it worked). Apply this rule if the sender is located outside the organization, and the recipient is located inside the organization and the sender’s specified properties includes any of the these words… Display Name XXXX or Display Name XXXX or Display Name XXXX (I listed out about 10). Then, do the following – prepend the disclaimer –

    ‘ Caution: This email originated from outside the organization AND has the same display name as someone inside our organization. This is probably a phishing email. Do not click on links, open attachments, or follow any instructions in this email. ‘; and fall back to action Wrap if the disclaimer can’t be inserted.

    Do you see something that I’m doing wrong? Thanks very much

    • Change this: the sender’s specified properties include any of these words
      To: A Message header matches > specify From > Add the display name

      You can also run the script, and change $displayNames = (Get-EXOMailbox -ResultSize unlimited -RecipientTypeDetails usermailbox).displayname to $displayNames = “Place Holder”

      This way the rule will be created in Exchange Online, allowing you to change the display names manually later on.

Leave a Comment

0 Shares
Tweet
Pin
Share
Share