Wednesday, March 30, 2011

Displaying Delegate Forward rule entries and removing any invalid entires with EWS and Powershell

This post follows on a little from a previous post where i was talking about invalid delegates. One thing the current EWS Rule operations in Exchange 2010 and also the Get-InboxRule cmdlets can't do is that both of these wont display any information about the delegate forward rule if its been configured. Now you can tell using the delegate operation if a forward rule has been configured for a user but this still doesn't read the rule object directly. You could question why you would want to do this if that's the case and the reason is usually when your trying to diagnose why somebody maybe geting a bounce message when meeting messages are being forwarded to an invalid mailbox user (eg a deleted delegate).

If you want to find what delegates the delegate rule is forwarding to you need to read these directly from the rule object. On Exchange 2010 you can access Folder Associated Items (FAI) and the Delegate rule object. In EWS to find this you can create a searchfilter and look for the FAI item where the PR_RuleMsgProvider_W property is set to "Schedule+ EMS Interface". Once there the address that a delegate is forwarded to are stored in the PidTagRuleMsgActions property which is documented in Rules protocol document http://msdn.microsoft.com/en-us/library/cc463893%28v=EXCHG.80%29.aspx . Parsing this property however is not trivial basically this property is a stream of serialized MAPI properties so one property that stores other properties such as PR_DisplayName and PR_EMAIL_ADDRESS_W. Fortunately i had a bit of experience and code from the FTS Stream parser i wrote and with some simple adaption this code can be more or less plugged in and returns all the properties and value parsed correctly. For the purpose of reading the delegates a forwarding rule is forwarding to PR_EMAIL_ADDRESS_W is the important property.

So to make this usable from Powershell I've created some cmdlets that first allows you to read the raw actions property on the delegate rule. Display any of these rules that are invalid it does this by using a EWS getdelegate operation and then comparing the valid entries retrieved with the delegate rules that exist. Then there is a unsupported remove cmdlet although the method I've used in not that bad basically what the remove does is if it finds one valid delegate in the delegate rule it forces an update of this delegate rule using an update delegate operation which will cause the delegate rule to be updated which will remove the invalid entry (as long as you have cleaned up the invalid delegates in Outlook or the other Remove-MessageOps.MailboxDelegatesInvalid.Unsupported cmdlet).


Get-MessageOps.MailboxDelegateForwardingRules: This cmdlet retrieves the MailboxDelegate Forwarding rules by finding the rules object in the associated folders collection of the Inbox and then parsing the actions MAPI property on this object. Note because of the limitation in EWS in 2007 this cmdlet will only work on Exchange 2010.

Example: Get-MessageOps.MailboxDelegateForwardingRules –p $ewsprofile –identity mailbox@domain.com

Get-MessageOps.MailboxDelegateInvalidForwardingRules: This cmdlet retrieves the MailboxDelegate Forwarding rules by finding the rules object in the associated folders collection of the Inbox and then parsing the actions MAPI property on this object. It then compares the entries contained in the forwarding rule to check if there is a valid delegate for this entry by using a getdelegates operation. Any users that don’t have a valid delegate entry is returned as invalid.
Example: Remove-MailboxDelegateInvalidForwardingRules –p $ewsprofile –identity mailbox@domain.com

Remove-MessageOps.MailboxDelegateInvalidForwardingRules.Unsupported: This cmdlet retrieves the MailboxDelegate Forwarding rules by finding the rules object in the associated folders collection of the Inbox and then parsing the actions MAPI property on this object. It then compares the entries contained in the forwarding rule to check if there is a valid delegate for this entry by using a getdelegates operation. If an invalid entry is found depending on the number of delegate entries the following action are taken.

· If other valid entries are found a update delegate operation is performed on one these entries which should make the sever side process remove the invalid entry when the forward rule is updated.

· If no other valid entries are found the rule object is deleted.

Example: Remove-MessageOps.MailboxDelegateInvalidForwardingRules.Unsupported –p $ewsprofile –identity mailbox@domain.com

To use these cmdlets you need to download the following module http://www.messageops.com/downloads/MessageOps-Exchange-Module.zip

8 comments:

Brij said...

Hello Glen,

I am using EWS managed APIs(Exchange 2010 SP1). I have to implement junk mail feature. Like reading/add/edit/delete safe sender list, Block sender/domains something similer like outlook. I tried your code given at http://social.technet.microsoft.com/Forums/en/exchangesvrdevelopment/thread/d2d8b559-a986-4ff2-8c30-892a849947cd
but could not read the property PidTagExtendedRuleMessageCondition property.
I have to read and add/edit/delete functionality. Can you provide me some sample code/more details on this.

Thanks a lot.

Glen said...

I don't have any code to parse that particular property on the Junk Email rule you need to use the protocol documents to work this out http://msdn.microsoft.com/en-us/library/cc425499%28v=exchg.80%29.aspx. As i mentioned in this post creating solutions like this is non trivial and takes a lot of effort I quoted someone this week 2.5 days of work to build a tested solution to properly modify the safe senders using EWS which is what i believe it would take possibly longer to do properply without risking corrupting the properties if you do hash job.

Cheers
Glen

Glen Mark Martin said...
This comment has been removed by the author.
Glen Mark Martin said...

I've been trying to use the EWS Managed API to read this information directly, but have encountered difficulties. I can find the rule whose PR_RULE_MSG_PROVIDER attribute is "Schedule+ EMS Interface", but I am unable to return the value for PR_RULE_ACTIONS. I'm wondering if this is because the data type PT_ACTIONS doesn't map to any of the MapiPropertyType values accepted by the extended property definition constructor. I've tried everything listed at http://msdn.microsoft.com/en-us/library/exchangewebservices.mapipropertytypetype(v=exchg.140).aspx , but the value is never returned.

I'm using these constructors for PR_RULE_MSG_PROVIDER and PR_RULE_ACTIONS (swapping out various mapi data types for the actions), but only the former is ever returned when I do a Load (verified by turning on tracing and looking at the XML returned):

# Properties for Hidden Delegate Forwarding Rule
$PID_TAG_RULE_MSG_PROVIDER = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x65EB,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
$PID_TAG_RULE_ACTIONS = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x6680,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)

#snip

If ($item.ExtendedProperties.Count -ge 1) {

If ($item.ExtendedProperties[0].Value -eq "Schedule+ EMS Interface") {
$forwardRuleExists = $true
write-host "Delegate forwarding rule found. Unable as of yet to enumerate contents." -ForegroundColor Cyan

Write-Host "Attempting to retrieve x6680 PR_RULE_ACTIONS (PidTagRuleActions)" -ForegroundColor Cyan
$PR_RULE_ACTIONS = $null
if($Item.TryGetProperty($Pid_Tag_Rule_Actions,[ref]$PR_RULE_ACTIONS)){

return $PR_RULE_ACTIONS
} # endif
else {write-error "TryGetProperty for PR_RULE_ACTIONS failed!"
} # endelse

return $item

} # End If - Correct Message

} # End If - Has Extended Properties
} # End ForEach
} # End If - Message Count

Glen Scales said...

I'm not sure where you getting the property value from ? have you look at the object with a MAPI editor the value I have

ExtendedPropertyDefinition(0x65EF, MapiPropertyType.Binary);

I'd suggest maybe you look at Redemption instead as well the one thing you can't do with EWS is access the Rule Table which is different from the Extended Rule object your trying to access

Glen Mark Martin said...

What I'm trying to get is the PidTagRuleActions property (aka PR_RULE_ACTIONS, 0x6880) from the delegate forwarding rule. I can find that rule just fine, matching the PR_RULE_MSG_PROVIDER attribute to "Schedule+ EMS Interface". Examining that rule in MfcMAPI, I can see the PR_RULE_ACTIONS property, but I don't see a 0x65EF.

Documented here:
http://msdn.microsoft.com/en-us/library/ee179623(v=exchg.80).aspx
http://msdn.microsoft.com/en-us/library/office/dd188673(v=office.15).aspx

Glen Scales said...

Your looking at the Rule Tables so you looking at the Standard rule abstraction.You need to understand there is a difference between what you view in the Rules Table and the Extended Rule object see more http://msdn.microsoft.com/en-us/library/ee202265%28v=exchg.80%29.aspx. With EWS you can't access the standard Rules Table directly you can only access it via the Rules Operations which offer and abstraction of what you can do in MAPI. If you want to access the Rules Table you need to use MAPI and your best option is to use Redemption if you trying to script it.

For the Delegate Rules you can access the Extended Rule object which is what I'm talking about in this post which is a FAI object in the inbox folder and then access the PR_EXTENDED_RULE_ACTIONS http://msdn.microsoft.com/en-us/library/ee218391(v=EXCHG.80).aspx property . As I said I would suggest you look at Redemption where you can access both the Rules Table and the Extended Rule Object correctly and you don't have to worry about how EWS has abstracted the MAPI interfaces.

Glen Mark Martin said...

Ah, that did the trick. I was missing out on the abstraction layer part. Many thanks.

Haven't looked Redemption yet. I'll definitely have to take it for a spin.