Playing Shell Dojo with Transport Rules


To enforce messaging policies, organizations frequently need to inspect messages based on different properties such as sender, recipients, subject, headers and attachments, and take the necessary actions such as adding disclaimers, adding headers, adding a prefix to the message subject, setting or modifying the SCL, adding a recipient, and rejecting a message. In Exchange 2007, we introduced transport rules to allow organizations to apply messaging policies, removing the need to write transport event sinks.

Exchange 2007 also introduced the Exchange Management Shell (EMS), built on Windows PowerShell, as a way to automate routine tasks and bulk operations. The shell uses a fairly simple syntax, and helps you perform tasks by using easy-to-understand cmdlets.

Exchange 2010 takes it further with many more capabilities, including the ability to manage your Exchange 2010 servers from a remote computer using Remote Shell. More details in Overview of Exchange Management Shell in Exchange 2010 documentation.

In this post, we’ll take a look at how transport rules can be created and managed in Exchange 2007, and how it’s been simplified in Exchange 2010. For creating one-off or a small number of transport rules, the transport rules wizard in EMC provides an easy-to-use interface. The shell can help you easily automate the process, and consistently create, test and implement transport rules. You can use the tool that best meets your needs.

Creating Transport Rules in Exchange 2007

In Exchange 2007, you create transport rules using the New-TransportRule cmdlet, and modify them using the Set-TransportRule cmdlet. However, the predicates used to create the conditions and exceptions for the rule, as well as the actions to be used in a rule, need to be instantiated first.

In this example, we create a transport rule to implement an ethical wall between the Brokers and Bankers distribution groups.

Before you create a transport rule, you must select the transport rule predicates and actions you want to use for the rule, and determine the predicate and action properties you will need to specify. You can either use the Get-TransportRulePredicate and Get-TransportRuleAction cmdlets, or refer to Transport Rule Predicates and Transport Rule Actions in Exchange 2007 documentation.

To create an ethical wall firewall, you need to use the BetweenMemberOf predicate. Let's find out the properties you must specify for this predicate.

Get-TransportRulePredicate BetweenMemberOf | fl

The output:

Addresses :
Addresses2 :
LinkedDisplayTextException : except when the message is sent between members of
distribution list and distribution list
Name : BetweenMemberOf
Rank : 6
LinkedDisplayText : between members of <a id="Addresses">distribution
list</a> and <a id="Addresses2">distribution list</a>

The BetweenMemberOf predicate requires you to specify two values— Addresses, and Addresses2.

  • Step 1: Instantiate the BetweenMemberOf predicate

    $condition = Get-TransportRulePredicate BetweenMemberOf

     

  • Step 2: Add the values to the new condition we instantiated. As seen in step 1, the BetweenMemberOf predicate requires two values— the identity of two distribution groups.

    $condition.Addresses = @(Get-DistributionGroup Brokers)
    $condition.Addresses2 = @(Get-DistributionGroup Bankers)

  • Step 3: Instantiate the RejectMessage action

    $action = Get-TransportRuleAction RejectMessage

  • Step 4: Add value to the action we instantiated

    $action.RejectReason = "Members of Bankers and Brokers distribution groups are not allowed to send email to each other."

  • Step 5: Create the new rule and add the instantiated condition and action to it.

    New-TransportRule -Name "EthicalWall" -Condition @($condition) -Action @($action)

Creating a Transport Rule in Exchange 2010

In Exchange 2010, we’ve made the following changes to the transport rule cmdlet experience based on your feedback.

  • You’re no longer required to instantiate predicates and actions
  • All predicates and actions are available in-line as parameters of the New-TransportRule and Set-TransportRule cmdlets, resulting in a much improved experience.
  • You can now create and modify transport rules using a single command!

Find The Parameter

Before we start creating rules using the shell, we must understand the relationship between predicates, predicate properties, and parameters. Remember, all properties are now parameters for the New-TransportRule and Set-TransportRule cmdlets! So, Properties = Parameters. The key is to determine the predicate or action you want to use and find the parameters it requires.

Exchange 2010 has many new predicates and actions. The Get-TransportRulePredicate and Get-TransportRuleAction cmdlets let you easily list them, and also determine the properties required for each. You can also look up Exchange 2010 predicates and actions in Transport Rule Predicates and Transport Rule Actions in Exchange 2010 documentation.

Using the Get-TransportRulePredicate cmdlet provides the following output:

Name Rank LinkedDisplayText
---- ---- -----------------
From 0 from <a id="From">people</a>
FromMemberOf 1 from a member of <a id="FromMemberOf">distribution list</a>
FromScope 2 from users that are <a id="FromScope">inside or outside the organization</a>
SentTo 3 sent to <a id="SentTo">people</a>
SentToMemberOf 4 sent to a member of <a id="SentToMemberOf">distribution list</a>
SentToScope 5 sent to users that are <a id="SentToScope">inside or outside the organization, ...
BetweenMemberOf 6 between members of <a id="BetweenMemberOf1">distribution list</a> and <a id="Be...
ManagerIs 7 when the manager of any <a id="ManagerForEvaluatedUser">sender</a> is <a id="Ma...
ManagementRelationship 8 when the sender is the <a id="SenderManagementRelationship">manager</a> of a re...
ADAttributeComparison 9 if the sender and recipient's <a id="ADComparisonAttribute">AD Attribute</a> ar...
RecipientAddressContainsWords 10 when a recipient's address contains <a id="RecipientAddressContainsWords">speci...
RecipientAddressMatchesPatterns 11 when a recipient's address matches <a id="RecipientAddressMatchesPatterns">text...
RecipientAttributeContains 12 when a recipient's <a id="RecipientADAttributeContainsWords">properties contain...
RecipientAttributeMatches 13 when a recipient's <a id="RecipientADAttributeMatchesPatterns">properties match...
AnyOfToHeader 16 when any of the recipients in the To field is <a id="AnyOfToHeader">people</a>
AnyOfToHeaderMemberOf 17 when any of the recipients in the "To" field is a member of <a id="AnyOfToHeade...
AnyOfCcHeader 18 when any of the recipients in the Cc field is <a id="AnyOfCcHeader">people</a>
AnyOfCcHeaderMemberOf 19 when any of the recipients in the Cc field is a member of <a id="AnyOfCcHeaderM...
AnyOfToCcHeader 20 when any of the recipients in the To or Cc fields is <a id="AnyOfToCcHeader">pe...
AnyOfToCcHeaderMemberOf 21 when any of the recipients in the To or Cc fields is a member of <a id="AnyOfTo...
HasClassification 22 marked with <a id="HasClassification">classification</a>
SubjectContains 23 when the Subject field contains <a id="SubjectContainsWords">specific words</a>
SubjectOrBodyContains 24 when the Subject field or message body contains <a id="SubjectOrBodyContainsWor...
HeaderContains 25 when the <a id="HeaderContainsMessageHeader">message header</a> contains <a id=...
FromAddressContains 26 when the From address contains <a id="FromAddressContainsWords">specific words</a>
SubjectMatches 27 when the Subject field matches <a id="SubjectMatchesPatterns">text patterns</a>
SubjectOrBodyMatches 28 when the Subject field or the message body matches <a id="SubjectOrBodyMatchesP...
HeaderMatches 29 when the <a id="HeaderMatchesMessageHeader">message header</a> matches <a id="H...
FromAddressMatches 30 when the From address matches <a id="FromAddressMatchesPatterns">text patterns</a>
AttachmentNameMatches 31 when any attachment file name matches <a id="AttachmentNameMatchesPatterns">tex...
SCLOver 32 with a spam confidence level (SCL) rating that is greater than or equal to <a i...
AttachmentSizeOver 33 when the size of any attachment is greater than or equal to <a id="AttachmentSi...
WithImportance 34 marked with <a id="WithImportance">importance</a>
MessageTypeMatches 35 if the message type is <a id="MessageTypeMatches">Message Type</a>
SenderAttributeContains 36 when the sender's <a id="SenderADAttributeContainsWords">properties contain spe...
SenderAttributeMatches 37 when the sender's <a id="SenderADAttributeMatchesPatterns">properties match tex...
HasNoClassification 38 not marked with a message classification<a id="HasNoClassification"></a>
AttachmentContainsWords 39 when an attachment's content contains <a id="AttachmentContainsWords">words</a>
AttachmentMatchesPatterns 40 when an attachment's content matches <a id="AttachmentMatchesPatterns">text pat...
AttachmentIsUnsupported 41 when an attachment is unsupported<a id="AttachmentIsUnsupported"></a>

Predicates can also be used as exceptions. Each predicate property (available as a transport rule parameter— e.g. BetweenMemberOf1 and BetweenMemberOf2, or From) also has an identical twin parameter with the prefix ExceptIf (for example, ExceptIfBetweenMemberOf1 and ExceptIfBetweenMemberOf2, or ExceptFrom). You can see how transport rule exceptions are used in some interesting ways in Steve Clagg's post Transport Rules: Exception to the Rule.

Similarly, using the Get-TransportRuleAction cmdlet lists all available actions:

Name Rank LinkedDisplayText
---- ---- -----------------
PrependSubject 0 prepend message subject with <a id="PrependSubject">string</a>
ApplyClassification 1 apply <a id="ApplyClassification">message classification</a>
ApplyHtmlDisclaimer 2 <a id="ApplyHtmlDisclaimerLocation">append</a> <a id="ApplyHtmlDisclaimerText">discla...
RightsProtectMessagev 3 rights protect message with <a id="ApplyRightsProtectionTemplate">RMS template</a>
SetSCL 4 set the spam confidence level to <a id="SetSCL">value</a>
SetHeader 5 set <a id="SetHeaderName">header</a> with <a id="SetHeaderValue">value</a>
RemoveHeader 6 remove <a id="RemoveHeader">header</a>
AddToRecipient 7 add a recipient in the To field <a id="AddToRecipients">addresses</a>
CopyTo 8 copy the message to <a id="CopyTo">addresses</a>
BlindCopyTo 9 Blind carbon copy (Bcc) the message to <a id="BlindCopyTo">addresses</a>
AddManagerAsRecipientType 10 add the sender's manager as a <a id="AddManagerAsRecipientType">specific</a> recipien...
ModerateMessageByUser 11 forward the message to <a id="ModerateMessageByUser">addresses</a> for moderation
ModerateMessageByManager 12 forward the message to the sender's manager for moderation<a id="ModerateMessageByMan...
RedirectMessage 13 redirect the message to <a id="RedirectMessageTo">addresses</a>
RejectMessage 14 send <a id="RejectMessageReasonText">rejection message</a> to sender with <a id ="Rej...
DeleteMessage 15 Delete the message without notifying anyone<a id="DeleteMessage"></a>

Once you've determined the predicate you need to use in a rule, you can list all the properties it requires. Some predicates require a single property, so the predicate name and the parameter name (used with New/Set-TransportRule cmdlets) are the same. For example, the From predicate takes a single property— an array of senders. The parameter is also called From. Some predicates require multiple properties. For example, the ADAttributeComparison predicate requires you to specify the name of the Active Directory attribute you want to compare, and a comparision operator (equal / not equal). The parameters are called ADComparisonAttribute and ADComparisonOperator.

You can simply cycle through (hit -, followed by the Tab key— known as "tab-complete" or "tab-through" in shell-speak... ) all available parameters of the New-TransportRule and Set-TransportRule cmdlets and chances are you would recognize the ones you need to use when they show up. If you remember the parameter name starts with the letter B, you can type that first letter and tab through all parameters starting with the letter B (New-TransportRule "Rule Name" -B + the Tab key to tab-through). You've just narrowed down the number of parameters to 3 - that's a lot less tabbing through.

This example lists properties of the the BetweenMemberOf predicate.

Get-TransportRulePredicate BetweenmemberOf | fl

The output (redundant information removed):

Addresses :
Addresses2 :
Name : BetweenMemberOf
Rank : 6
LinkedDisplayText : between members of <a id="BetweenMemberOf1">distribution list</a> and <a id="BetweenMemberOf2">distribution list</a>

The LinkedDisplayText is the predicate description you see on the Conditions page in the EMC rules wizard (see Figure 1). The properties required are enclosed in <a> and </a> tags in the LinkedDisplayText. The predicate requires 2 properties – Addresses and Addresses2. The parameter names for these properties (shown as the link ids) are called BetweenMemberOf1 and BetweenMemberOf2. The link text shown in EMC is distribution list for both properties - indicating the type of values required.


Figure 1: The LinkedDisplayText is the predicate description displayed in the EMC rules wizard. The two properties required for this predicate are called BetweenMemberOf1 and BetweenMemberOf2.

Ditto for all properties of an action. This example lists properties of the the RejectMessage action.

Get-TransportRuleAction RejectMessage | fl

The output:

RejectReason : Delivery not authorized, message refused
EnhancedStatusCode : 5.7.1
Name : RejectMessage
Rank : 14
LinkedDisplayText : send <a id="RejectMessageReasonText">rejection message</a> to sender with <a id ="RejectMessageEnhancedStatusCode">enhanced status code</a>

The RejectMessage action requires two properties - RejectReason and EnhancedStatusCode. The parameters are named RejectMessageReasonText and RejectMessageEnhancedStatusCode. The LinkedDisplayText is the action description shown on the Actions page in the rules wizard in EMC (see Figure 2). If a value isn't specified for the EnhancedStatusCode, the default value is 5.7.1.


Figure 2: The LinkedDisplayText is the action description displayed in the EMC rules wizard. The two properties required for this action are called RejectMessageReasonText and RejectMessageEnhancedStatusCode.

Let's create the same transport rule in Exchange 2010.

New-TransportRule -Name EthicalWall -BetweenMemberOf1 Brokers -BetweenMemberOf2 Bankers -RejectMessageReasonText "Members of Bankers and Brokers distribution groups are not allowed to send email to each other."

Yes, that's it - it's a one-liner!

Common Errors

The more common error you may make when creating rules is not specifying all parameters required for a predicate. For example, you may specify the BetweenMemberOf1 parameter, but not BetweenMemberOf2. Luckily, the shell provides some great to-the-point feedback in such cases.

When the BetweenMemberOf1 parameter is specified, the following parameters must also be specified: BetweenMemberOf2.
   + CategoryInfo : InvalidArgument: (BetweenMemberOf1:String) [New-TransportRule], ArgumentException
   + FullyQualifiedErrorId : 760A4623,Microsoft.Exchange.MessagingPolicies.Rules.Tasks.NewTransportRule

Another common error is specifying an incorrect value for a parameter, when the cmdlet expects a value from a fixed list of values. In this example, we've provided an incorrect value ("foo") for the ADComparisonAttribute parameter. In such cases, the shell lists all the correct values, as shown in the following example.

Cannot process argument transformation on parameter 'ADComparisonAttribute'. Cannot convert value "foo" to type "Microsoft.Exchange.MessagingPolicies.Rules.Tasks.ADAttribute" due to invalid enumeration values. Specify one of the following enumeration values and try again. The possible enumeration values are "DisplayName, FirstName, Initials, LastName, Office, PhoneNumber, OtherPhoneNumber, Email, Street, POBox, City, State, ZipCode, Country, UserLogonName, HomePhoneNumber, OtherHomePhoneNumber, PagerNumber, MobileNumber, FaxNumber, OtherFaxNumber, Notes, Title, Department, Company, Manager, CustomAttribute1, CustomAttribute2, CustomAttribute3, CustomAttribute4, CustomAttribute5, CustomAttribute6, CustomAttribute7, CustomAttribute8, CustomAttribute9, CustomAttribute10, CustomAttribute11, CustomAttribute12, CustomAttribute13, CustomAttribute14, CustomAttribute15".
   + CategoryInfo : InvalidData: (:) [New-TransportRule], ParameterBindin...mationException
   + FullyQualifiedErrorId : ParameterArgumentTransformationError,New-TransportRule


Figure 3: Certain properties require a value from a fixed set of values. In EMC, these can be selected from a drop-down list. If you specify an unexpected value when using the shell, a list of all correct values is provided.

View Transport Rules

The Get-TransportRule cmdlet retrieves a list of all transport rules. As a result of having all predicate and action properties available as parameters, when you use the Get-TransportRule cmdlet to view the properties of a transport rule (Get-TransportRule <rule name> | fl, where fl is short for the format-list cmdlet), you’ll see the large number of parameters scroll by rather quickly, making it difficult to determine which parameters are actually used for the cmdlet. This is a tradeoff we had to make when redesigning the cmdlet experience for transport rules.

However, there’s an easy workaround. Each rule has the Conditions and Actions properties which list the predicates and actions used. This example retrieves the rule conditions.

(Get-TransportRule EthicalWall).Conditions | fl

The output:

Addresses : {Brokers@contoso.com}
Addresses2 : {Bankers@contoso.com}
Name : BetweenMemberOf
Rank : 6
LinkedDisplayText : between members of <a id="BetweenMemberOf1">distribution list</a> and <a id="BetweenMemberOf2">distribution list</a>

You can use (Get-TransportRule <rule name>).Exceptions to list all exceptions and (Get-TransportRule <rule name>).Actions to get a list of all actions specified in the rule. This example does not use any exceptions. The following output shows the actions:

RejectReason : Members of Bankers and Brokers distribution groups are not allowed to send email to each other.
EnhancedStatusCode : 5.7.1
Name : RejectMessage
Rank : 14
LinkedDisplayText : send <a id="RejectMessageReasonText">rejection message</a> to sender with <a id ="RejectMessageEnhancedStatusCode">enhanced status code</a>

Having all predicate properties and actions available as parameters also allows you to filter the rules based on these parameters. For example, to get a list of all transport rules where the Brokers distribution group is used in the BetweenMemberOf predicate:

Get-TransportRule | Where {$_.BetweenMemberOf1 -like "*Brokers*" -or $_.BetweenMemberOf2 -like "*Brokers*"}

Or you can list all transport rules that perform a particular action. This example lists all transport rules that use the RejectMessage action.

Get-TransportRule | Where {$_.RejectMessageReasonText -ne $null}

Modify a transport rule

Now you can use the Set-TransportRule cmdlet and modify the –BetweenMemberOf and/or –BetweenMemberOf2 parameters, and specify different distribution groups. You can also add additional predicates to the condition, or add exceptions. This example adds the additional predicate SubjectOrBodyContains so only messages that are sent between the two distribution groups AND with the word "trade" in the message subject or body are blocked by the rule.

Set-TransportRule EthicalWall -SubjectOrBodyContainsWords "trade"

If you decide not to use the BetweenMemberOf predicate, you can remove it by setting both its properties to $null.

Set-TransportRule EthicalWall –BetweenMemberOf1 $null –BetweenMemberOf2 $null

Note: If you don’t use any predicates or exceptions in a rule, the rule applies to all messages.

Enable, Disable and Remove Transport Rules

You can use the Enable-TransportRule and Disable-TransportRule cmdlets to enable or disable transport rules.

Enable-TransportRule EthicalWall

When disabling a transport rule using the Disable-TransportRule cmdlet, you’re greeted with a confirmation prompt. You can override the prompt using the –Confirm parameter.

Disable-TransportRule EthicalWall –Confirm:$false

This example disables all transport rules and overrides the confirmtaion prompt.

Get-TransportRule -State Enabled | Disable-TransportRule –Confirm:$false

Similarly, you can remove transport rules using the Remove-TransportRule cmdlet.

Change Transport Rule Priority

Tranpsort rules are executed by the rules agents on the Hub and Edge Transport servers based on their priority, in ascending order. The lowest priority value is 0, assigned to the first transport rule you create. For each successive rule you create, the priority is incremented by 1. You can change the priority of a rule to change the rule execution order. The priority values for other transport rules is adjusted (increased or decreased) depending on the new priority you assign to the rule you’re modifying.

For example, if you have 4 transport rules called EthicalWall1, EthicalWall2, EthicalWall3 and EthicalWall4, with the default priority assigned at creation (0 for EthicalWall1 and 3 for EthicalWall4). If you want to ensure the EthicalWall2 rule is executed last, you can use Set-TransportRule cmdlet to modify rule priority

Set-TransportRule EthicalWall2 -Priority 3

Remember, the highest priority is n-1, where n is the total number of rules. This also allows you to easily determine the total number of transport rules. Use Get-TransportRule | Select -Last 1. The total number of rules = priority of last rule + 1. Alternatively, you can use (Get-TransportRule).count.

Getting all parameters for a cmdlet

Here's a tip that many shell jockeys find useful. During Exchange 2007 development, I found myself frequently asking the same question— How can I list all the parameters for a cmdlet? Cmdlet help (Using Get-Help <Cmdlet Name> -Full or -Detail) would show me a lot of details, including the parameter name, type, description, examples, etc. — but I just need the list of all parameters! Cmdlet reference documentation has all this information, well-formatted and perhaps more readable than Shell output, but it requires firing up a browser window. Most shell jockeys would consider that inefficient! It wasn’t quite possible in Exchange 2007.

In Exchange 2010, you can get a list of parameters for any cmdlet using the following syntax.

(Get-Command <Cmdlet Name>).Parameters

For example, to get a list of all parameters for the New-TransportRule cmdlet:

(Get-Command New-TransportRule).Parameters

So, how many parameters does New-TransportRules cmdlet have? Use the following command to find out!

(Get-Command New-TransportRule).Parameters.Count

Bharat Suneja

Comments (2)
  1. Gigi says:

    Wow! I think this is the longest article so far. Nice post!

  2. GALE says:

    Excellent post! Great to find this so simplified.

Comments are closed.

Skip to main content