MAPI in the registry (Or, setting the "use HTTP first" boxes via VBScript)

First off, I didn't use PowerShell because I use the script in this article as a login script - and while I'm sure that the Windows Scripting Host is installed everywhere, I can't be sure that PowerShell is installed everywhere. It will be a couple of years before I can do that.

Beginning with Exchange 2003 and Outlook 2003 (when running on Windows 2003), you could use RPC/HTTP (the feature was renamed to Outlook Anywhere with Exchange 2007). RPC/HTTP provides the capability of encapsulating the native protocol that Outlook uses to communicate with Exchange Server with a secure HTTP tunnel. Long story short, it's a way of safely getting around firewalls.

The name of the protocol that Outlook prefers to use with Exchange Server is called MAPI - Message Applications Programming Interface. Let's suffice it to say that MAPI is very powerful, very extensible, allows you to do darn near anything with a message or with Exchange that you might ever want to, and as is typical with all that power - MAPI is complicated to use. And you won't be using MAPI in a script!

I can't give MAPI justice in a blog post. But let's talk about a few basic MAPI concepts.

Providers - a MAPI provider is some type of a server process (note: this does NOT mean that it has to run on a server, just that it provides services to clients). A few sample MAPI providers include the Address Book provider, the Spooler (which queues and sends email to Exchange), and the Profile provider (which is responsible for managing Mail profiles on a per-user basis on a client workstation).

Profile - a MAPI profile defines everything that a messaging client (such as Outlook) may need to know about communicating with an email server. A single profile may contain information about all of the various providers available to the client, both locally and on remote servers.

Property - a MAPI property is no different than any other type of property. It contains a value that is relevant to a specific provider and that value is contained within a specific profile. In general, a MAPI property is referred to via something called a PROP_TAG (a property tag) which is a 32 bit binary value. The first 16 bits represent the type of the property (such as integer or string, etc.) plus a special flag bit or two. The second 16 bits of a property is the specific property identifier.

The profile provider, which can be accessed via raw MAPI (of course), uses the system registry to store information about MAPI properties, profiles, providers, and other MAPI objects. Officially, these items are opaque. However, they have been the same since Windows 95, so it's unlikely that they will be changing any time soon.

In the registry, each MAPI service associated with a particular profile has a GUID, which is a string. The particular GUID is assigned to the MAPI service, and is consistent across all MAPI installations. Each MAPI service has a series of property values assigned to it, and those property tags are represented by an 8-character value which is the hexidecimal representation of the binary property tag.

Today, we are particular interested in a single MAPI service - the Exchange Server Details MAPI service. This service is responsible for the connectivity to an Exchange server via the MAPI protocol. It has the following GUID:

Const ExchDetails = "13dbb0c8aa05101a9bb000aa002fc45a"

EVERY MAPI profile which connects to an Exchange server will have that MAPI service defined and its property values populated. The particular MAPI property we are interested in is named PR_ROH_FLAGS. It looks like this:

Const PT_LONG         = "0003"           ' hex MAPI type for a 4-byte binary value

PR_ROH_FLAGS          = PT_LONG & "6623" ' PROP_TAG (PT_LONG, 0x6623)

therefore the resultant value for PR_ROH_FLAGS is 00036623. Any MAPI profile which currently (or ever) was using RPC/HTTP (Outlook Anywhere) will have this property present. This flags value contains a number of documented (and conceivably undocumented) flags. They are:

'' Connect to my Exchange mailbox by using HTTP.
Const ROHFLAGS_USE_ROH            = &h1

'' Connect by using SSL only.
Const ROHFLAGS_SSL_ONLY           = &h2

'' Mutually authenticate the session when connecting by using SSL.
Const ROHFLAGS_MUTUAL_AUTH        = &h4

'' On fast networks, connect by using HTTP first. Then, connect by using TCP/IP.

'' On slow networks, connect by using HTTP first. Then, connect by using TCP/IP.

You should note that the first flag (ROHFALGS_USE_ROH) indicates whether or not RPC over HTTP is enabled within this profile. The second flag (ROHFLAGS_SSL_ONLY) will always be set in the current implementation. If the ROHFLAGS_MUTUAL_AUTH flag is set, it means that both the client and the server will authenticate to each other.

The last two flags are the ones we are interested in... ROHFLAGS_HTTP_FIRST_ON_FAST and ROHFLAGS_HTTP_FIRST_ON_SLOW. They define whether HTTP is tried first, or TCP is tried first. If the boxes are checked, the flags are set. Conversely, if the flags are set, the boxes will be checked. Therefore, our goal is to make sure those flags are set.

Especially if you are using Basic authentication, having these flags set can result in faster Outlook startup time.

By default, Autodiscover in Exchange 2007 and above will set the ROHFLAGS_HTTP_FIRST_ON_SLOW flag, but not set the ROHFLAGS_HTTP_FIRST_ON_FAST flag. There is no way to change this behavior.

The following script is much longer than an equivalent script in PowerShell would be, and it's longer than it has to be in VBScript, but I wanted to make it easy to understand and provide resources for other scripters wanting to make profile modifications.

Obligatory disclaimers:

Modifying your registry can break your computer.

Modifying MAPI properties by modifying the registry may not be supported, I really don't know. It works for me and my clients, but I can't guarantee that it will for you.

On to the script:

'' httpFirstAlways.vbs
'' Michael B. Smith
'' July, 2009
'' No warranties express or implied are available.
'' Use at your own risk - but it works for me!
'' This routine, for the current user, scans through all Exchange profiles. If
'' the RPC over HTTP (Outlook Anywhere) flags value is present, this means that
'' RPC over HTTP is configured for the profile. If the flag is present, this
'' routine will force "On fast networks, connect using HTTP first" and "On slow
'' networks, connect using HTTP first" to be checked.
Const ProfilePath = "Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles"
Const ExchDetails = "13dbb0c8aa05101a9bb000aa002fc45a" ' Exchange Server Details MAPI service

Const PT_LONG     = "0003" ' hex MAPI type for a 4-byte binary value
COnst PT_UNICODE  = "001f" ' hex MAPI type for a Unicode string

' Used to configure cached mode, but not used in this script

Dim PR_CONFIG_FLAGS          ' configuration flags for the Exchange Server Details MAPI service

PR_CONFIG_FLAGS          = PT_LONG    & "6601" ' PROP_TAG (PT_LONG, 0x6601)

'' MAPI properties for RPC over HTTP
'' From KB 898835 - MAPI properties for RPC over HTTP settings

Dim PR_ROH_FLAGS             ' RPC over HTTP flags
Dim PR_ROH_PROXY_SERVER      ' RPC over HTTP proxy server
Dim PR_ROH_PRINCIPAL_NAME    ' Primary name on the SSL certificate 

PR_ROH_FLAGS             = PT_LONG    & "6623" ' PROP_TAG (PT_LONG,    0x6623)
PR_ROH_PROXY_AUTH_SCHEME = PT_LONG    & "6627" ' PROP_TAG (PT_LONG,    0x6627)

'' Flags that are used in PR_ROH_FLAGS
'' Connect to my Exchange mailbox by using HTTP.
Const ROHFLAGS_USE_ROH            = &h1
'' Connect by using SSL only.
Const ROHFLAGS_SSL_ONLY           = &h2
'' Mutually authenticate the session when connecting by using SSL.
Const ROHFLAGS_MUTUAL_AUTH        = &h4
'' On fast networks, connect by using HTTP first. Then, connect by using TCP/IP.
'' On slow networks, connect by using HTTP first. Then, connect by using TCP/IP.

'' Values that are used in PR_ROH_PROXY_AUTH_SCHEME
'' Basic authentication
Const ROHAUTH_BASIC               = &h1
'' NTLM authentication
Const ROHAUTH_NTLM                = &h2

Const HKEY_CURRENT_USER = &h80000001

Set objReg = GetObject ("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")

objReg.EnumKey HKEY_CURRENT_USER, ProfilePath, arrSubKeys

For Each objSubKey in arrSubKeys

	strMAPIpropKey   = ProfilePath  & "\" & _
                           objSubKey    & "\" & _

        strMAPIpropValue = PR_ROH_FLAGS

	e "Checking profile named " & objSubKey

	On Error Resume Next

	objReg.GetBinaryValue HKEY_CURRENT_USER, strMAPIpropKey, strMAPIpropValue, arrBinary

	On Error Goto 0

	If IsNull (arrBinary) Or Err Then
		e " value not found"
		'e "Values (" & UBound (arrBinary) & ")"
		'For i = 0 To UBound (arrBinary)
		'	e i & " " & arrBinary(i) & " " & Hex(arrBinary (i))

		val = arrBinary (0)
			e "...On fast networks, connect using HTTP first --- IS SET"
		End If

			e "...On slow networks, connect using HTTP first --- IS SET"
		End If


		If (val and bitVal) = bitVal Then
			e "...Desired options are already set"
			e "...Updating"
			arrBinary(0) = arrBinary(0) Or bitVal
			result = objReg.SetBinaryValue (HKEY_CURRENT_USER, strMAPIpropKey, strMAPIpropValue, arrBinary)
			If result <> 0 Then
				e "...Could not update HTTP network value (" & result & ") !!!"
				e "...update complete"
			End If
		End If

	End If

e "Done"

Set objReg = Nothing

Sub e(str)
	WScript.Echo str
End Sub

Until next time...

If there are things you would like to see written about, please let me know!

P.S. Thanks to Diane Poremsky and John Fullbright for assistance in creating this article.

Published Tuesday, July 21, 2009 4:36 PM by michael


No Comments