Wednesday, July 18, 2007

Turning on Filter Junk Email in Exchange 2007 via an OWA Script

In the past I’ve posted a few scripts for setting and reading the OWA junk email filter settings here. While content filtering and the IMF have changed in Exchange 2007 there are still no cmdlets that will allow you to flip this option on or off for users so this little script still can come in handy for various situations. Because OWA was rewritten from the ground up in Exchange 2007 the old script method no longer works. However the same methods of reverse engineering the OWA method do work with a few additions.

Using the MSXML2.ServerXMLHTTP.6.0 object this object is included with the Microsoft XML Parser (MSXML) and is a better choice for this script because it firstly supports the ability to ignore any SSL errors that might happen (eg self signed Certs, Alternate names etc) and it also handles dealing with the Forms Based Authentication cookie without the necessity to add additional code. The code still needs to perform the synthetic forms logon this works similar to 2003 with a few URL tweaks.

Dealing with the Language form for users who have never logged on to OWA before. Because this script is simulating a user in OWA if the mailbox your trying to set the junk email settings has never been logged onto before in OWA then the default language form will be presented to the user (or the script in this case) asking the person to choose there timezone and language. What this script does to cater for this is that it looks for this form in the response if it finds the form it then uses 2 regular expressions to parse the default values from the form and then posts these values. One problem this creates is that the user will nolonger be shown this form when they first logon anymore this may or may not be a problem for you. If you need for this form to still appear at first logon there are two options the first is to delete the OWA storage object in the root of the mailbox using WebDAV or Neil Hobson posted another method on the Exchange Blog.

The operation of the script is pretty simple after logging in it tries to post to the following URL QueryString in the Target Mailbox “/ev.owa?oeh=1&ns=JunkEmail&ev=Enable” with a body

"<params><fEnbl>1</fEnbl></params>"

This will enable junk email filtering on a mailbox to disable junk email filtering use

"<params><fEnbl>0</fEnbl></params>"

To use this script you need to hard code the username and password of a user that has been give delegate access to the target mailbox using something like this in the Exchange Command Shell

Add-MailboxPermission –Identity ‘Mailbox’ –User ‘User’ –AccessRights FullAccess

Or has been given Send As and Receive As rights on the target mailbox. Basically the user needs to be able to open the target mailbox as another mailbox in OWA you can test if the account you want to use is going to be work by testing this yourself in OWA. Its also important that the account that you want to use has logged onto OWA once as well this is because the Language form would be presented to this user the first time the user tries to logon to OWA while the script caters for this for the target user it doesn’t do it for the source so this would cause a timeout error in the case the source user has never logged on to OWA. So before using the script you need to configure the following variables

snServername = "ServerName"
mnMailboxname = "mailbox"
domain = "domain"
strpassword = "password"

In the snServername variable make sure you use the servername of your CAS server this may or may not be different from your mailbox server.

The following variable is for the target mailbox you want to set the junkemail setting on this should be the primary SMTP address of the target mailbox

Targetmailbox = "user@domain.com"

The scripts output is pretty verbose you should see the full response headers outputted for each request the script make this helps if you ever need to diagnose why the script isn’t working

I’ve put a downloadable copy of the script here the script itself looks like

snServername = "ServerName"
mnMailboxname = "mailbox"
domain = "domain"
strpassword = "password"

strusername = domain & "\" & mnMailboxname
szXml = "destination=https://" & snServername & "/owa/&flags=0&username=" &
strusername
szXml = szXml & "&password=" & strpassword & "&SubmitCreds=Log On&forcedownlevel=0&trusted=0"


set req = createobject("MSXML2.ServerXMLHTTP.6.0")
req.Open "post", "https://" & snServername & "/owa/auth/owaauth.dll", False
req.SetOption 2, 13056
req.send szXml

reqhedrarry = split(req.GetAllResponseHeaders(), vbCrLf,-1,1)
for each ent in reqhedrarry
wscript.echo ent
Next

Call UpdateJunk("user@domain.com")

Sub UpdateJunk(mbMailbox)

xmlstr = "<params><fEnbl>1</fEnbl></params>"

req.Open "POST", "https://" & snServername & "/owa/" & mbMailbox & "/ev.owa?oeh=1&ns=JunkEmail&ev=Enable",
False
req.setRequestHeader "Content-Type", "text/xml; charset=""UTF-8"""
req.setRequestHeader "Content-Length", Len(xmlstr)
req.send xmlstr
wscript.echo req.status
reqhedrarry = split(req.GetAllResponseHeaders(), vbCrLf,-1,1)
for each ent in reqhedrarry
wscript.echo ent
Next
If InStr(req.responsetext,"name=lngFrm") Then
wscript.echo "Mailbox has not been logged onto before via OWA"
'Create a regular expression object
Dim objRegExp
Set objRegExp = New RegExp

'Set our pattern
objRegExp.Pattern = "<option selected value=""(.*?)"">"
objRegExp.IgnoreCase = True
objRegExp.Global = True

Dim objMatches
Set objMatches = objRegExp.Execute(req.responsetext)
If objMatches.count = 2 then
lcidarry = Split(objMatches(0).Value,Chr(34))
wscript.echo lcidarry(1)
tzidarry = Split(objMatches(1).Value,Chr(34))
wscript.echo tzidarry(1)
pstring = "lcid=" & lcidarry(1) & "&tzid=" & tzidarry(1)
req.Open "POST", "https://" & snServername & "/owa/" & mbMailbox & "/lang.owa",
False
req.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
req.setRequestHeader "Content-Length", Len(pstring)
' req.SetRequestHeader "cookie", reqCadata
req.send pstring
if instr(req.responsetext,"errMsg") then
wscript.echo "Permission Error"
else
wscript.echo req.status
If req.status = 200 and not instr(req.responsetext,"errMsg") Then
Call UpdateJunk(mbMailbox)
Else
wscript.echo "Failed to set Default OWA settings"
End if
end if

Else
wscript.echo "Script failed to retrieve default values"
End if
Else
wscript.echo "Junk Mail Setting Updated"
End if
End sub


26 comments:

Anonymous said...

I guess I am confused as to how this works. I tried it but even though it says it was successful it is not. Could you give us an example of what to fill in for the different variables and then what the outcome would be, please?

Glen said...

If you are logged into OWA make sure that you log off and then log back on to check the result Its something to do with the way the Ajax client caches.

The variables you need to fill out are

casServerName = "servername"
mnMailboxname = "username"
domain = "domain"
strpassword = "password"

Targetmailbox = "fred@domain.com.au"

You should see something similar to

Content-Length: 0
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Tue, 21 Aug 2007 04:40:52 GMT


200
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Expires: -1
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
X-OWA-Version: 8.1.85.4
X-OWA-EventResult: 0
Set-Cookie: UserContext_9588527c47764574b1e8ac1ee2f8b134=c25feb0f024c43e48b1afd5
21d544007&c210cDpkYXZlQGUyMDA3ZGV2LmNvcmUubWFuYWdlbmV0LmNvbS5hdQ; path=/
Date: Tue, 21 Aug 2007 04:40:52 GMT


Junk Mail Setting Updated

as output the important thing being that the cookies are being set.

Cheers
Glen

cannedsoda said...

Glen, I'm getting this. Using forms auth. I'm guessing something in the set req isn't quite right.

Set-Cookie: sessionid=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT
Set-Cookie: cadata=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT
Content-Type: text/html
Connection: close
Content-Length: 154


440
Date: Mon, 27 Aug 2007 17:52:53 GMT
Server: Microsoft-IIS/6.0
Set-Cookie: sessionid=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT
Set-Cookie: cadata=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT
Content-Type: text/html
Connection: close
Content-Length: 43


Junk Mail Setting Updated

Glen said...

It looks like the Cookies aren't being set correctly. Had the account you're trying to set ever been logged on to before. I've only tried this on the English version of Exchange the regex stuff may fail if your using a language other then English.

To try an work out what might be going wrong you could try push up the output from the cmd. eg

if you add some

wscript.echo req.responsetext

after the

wscript.echo req.status

You should see the full output of whats being returned. Could be something funny to do with the entry page which is why the cookies may not be getting set as expected.

Marcusiess said...

The script works great. I'm having trouble finding a way to update a list of email addresses using this script. I am executing this via cmd line using cscript owajmail2007v2.vbs . Is there an easy way to have this update a list instead of just one?

Anonymous said...

Glen --

We are seeing a 401 authentication error unless the Outlook Web Access web site has Forms-Based authentication (Logon Format: Domain\user name) enabled in the Exchange Management Console under:

Server Configuration->Client Access->Outlook Web Access->AUTHENTICATION tab.

Is it possible to make this work with standard integrated/basic authentication? We have to use standard since we publish OWA using ISA 2006. Thanks!

Glen said...

Have a look at http://msgdev.mvps.org/exdevblog/owajmail2007noFBA.zip

these mods should make it work okay with one proviso. The ServerXMLHTTP wont sent the NTLM credentials to the server unless is believes its on the local network so you also need to run proxycfg -d -p " " "*" at the cmdline first to configure the object to send the credentials. Otherwise you could switch to using the microsoft.xmlhttp object. The problem with this object is you need to make sure you trust the SSL cert that your server is using this may or may not be a problem for you. If you do use this object rem out the Setoption line.

Cheers
Glen

Cheers
Glen

Kirrin Jones said...

Hi Glen,

Is there a script like this for Exchange 2003?

Glen said...

Sure have a look at http://blogs.technet.com/evand/archive/2005/01/31/363935.aspx

Cheers
Glen

Anonymous said...

Script is great. I just wonder, what houl I change to use it also to change default OWA search capabilities from GAL to contacts?

Cheers

Konrad

Anonymous said...

Hi Glen!

Script is great!

Is it possible to assign a new rule with the following items
Name SPAM
Subject containing word(s) SPAM
Automove to JunkEmailFolder

?

Cheers!

Alf

Glen said...

see http://groups.google.com.au/group/microsoft.public.exchange2000.development/browse_thread/thread/a3deefc864238e3e

Cheers
Glen

Anonymous said...

Thanks Glen!

I forgot to mention that it is for Exchange 2007.

By the way I figured out a simpler way with no code.

1: Enabling Content filtering on HUB after installing "install-AntispamAgents.ps1" (file is under Folder scripts where Exchange is installed)

2: set-mailbox -Identity "user" -SCLJunkEnabled:$true -SCLJunkThreshold:3

3: Creating a Tranport Rule From the Exchange Management Console
Conditions:
Where the Subject contains specific words "SPAM"
Actions:
set the spam confidence level to "4"
Exceptions: none

Update Rule/Finish

Messages are filtered with SpamAssassin, adding *SPAM on subject field, the Exchange Trasport filter Rule adds SCL 4, the UserMailbox has SCLThreshold 3, all above 3 are moved to Folder Junk-Email.

And with your Code activating the OWA Junk-email setting, It can't be better:)

Cheers

Alf

Anonymous said...

It is posible to run this script for all users in exchange server?, or for a limited group or something, the idea is to do a batch work.

tks,

Glen said...

There is a Powershell port of this you can combine with Get-Mailbox to do other Exchange cmdlet that allow you to filter it anyway you like

http://poshcode.org/830

Cheers
Glen

Karl Gagnon said...

Hi Glen,

I work for an Hosted Exchange 2007 company and we're modifying the way our incomming emails are filtered.

We have a third-party solution that scan all our incomming emails and we want to have flagged emails (using Transport Rules to set the spam confidence level) moved into Junk Email folder. So to resume, when the am confidence level is X, we want those emails moved to Junk Email folder.

For now the only way we were able to make it work is by modifying the Junk E-Mail options into OWA (Automatically filter junk e-mail).

As you can understand, we can't ask to our 70000 users to change this setting. So we want to have a way to do it server side.

I have take a look at your script but I'm surprise that this is the only way to have the flagged emails move to the Junk Email Folder..

Is there something I don't understand..?

Do you know how we can have flagged emails move to the Junk Email Folder?

Thanks for your help.

Karl

Glen said...

This has nothing to do with Flagged email rather this script will switch the Microsoft Junk Email rule on. If you have you own SPAM flags then you need to look at Mapi rule http://objectmix.com/microsoft-exchange/268091-how-create-exchange-2000-mailbox-rules-programmatically.html.

If you are trying to switch the Microsoft Junk Email rule on then i would suggest you take a look at the powershell port
http://poshcode.org/830 which is more appropriate if you have to do this on a large number of mailboxes.

Cheers
Glen

Karl Gagnon said...

Hi Glen,

Thank you so much for your answer. Can you confirm that rule.dll is working on Exchange 2007 as well?

thanks!

Best regards and Happy new year.

Karl

Glen said...

Yes Rule dll will work with 2007 although you should understand this dll is more to do with the client Mapi rather then the server. RDO/Redemption can also be used and has the advantage of working in Powershell.

Cheers
Glen

Anonymous said...

Hi Glen!

And HAPPY NEW YEAR!

Is it possible to get a list of all available params? by running Your script?

fEnbl is for the Filter Junk E-mail option, Do You have a list of the rest params for the rest of options in OWA 2007/2010 and their possible values?

Cheers

Alf

Glen said...

Not sure if this will work against a 2010 box. This is all undocumented so you pretty much need to work out what they are yourself. Look at using something like fiddler to work it out.

Cheers
Glen

Anonymous said...

Is there a way to use your pshell script to disable instead of enable? How could I modify to do this as I'm not amazing with pshell scripting.

Glen said...

If you want to disable it you need to set the line

"0"

the 0 disables the rule

Cheers
Glen

Anonymous said...

Im using 2007 and enabling the junk e-mail works great in the v2 script. How can I add to the safe senders list and safe recipients list?

Glen said...

see http://gsexdev.blogspot.com/2008/09/adding-entries-to-safe-sendersafe.html

Cheers
Glen

Lars Panzerbjørn said...

Thanks for the article, it was an interesting read.

I'm currently trying to find out how to see, and change, what junk mail level our users have set -_-