The question was recently posed on a mailing list asking whether there was any book that covered the Exchange 2003 security model in depth.

The question came up for the poster because of a recent video that is making the rounds on youtube and elsewhere (http://www.thewebsiteisdown.com). In that video, an errant system administrator deletes a message from his bosses Sent Items folder, so that the boss cannot verify that the administrator was told something specific.

Can that happen??? Well - yes. And it isn't unique to Exchange Server. And yes, that administrator should be fired.

A savvy Exchange administrator, who also has appropriate permissions in Active Directory, can assign herself permissions at any level of an Exchange organization - per mailbox, per mailbox store, per storage group, per server, or for the entire Exchange organization.

While the backend permission sets have expanded dramatically in Exchange Server 2007, the store and user permissions are still quite similar to Exchange Server 2003. There are three whitepapers at Microsoft that can help you learn about the various permissions and how they work within themselves and within Active Directory:

Exchange Server 2003 Technical Reference Guide

Working with Active Directory Permissions in Microsoft Exchange Server 2003

Working with Store Permissions in Microsoft Exchange 2000 and 2003

Another resource is Alain Lissoir's web site. Alain wrote a couple of great white papers on scripting in Exchange 2000 and 2003 and they contain some excellent security related resources.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | with no comments

I'm in the process of tech-reviewing an important book (you'll want it on your shelf once it is released), and one of the things I did today was spend a while figuring out how to do Attribute Scoped Queries in PowerShell. If you develop in C# or C++, or use adfind to do your searches, those tools have supported ASQs for a long time.

I use PowerShell quite a bit for Exchange Server 2007+ maintenance tasks, but I am no expert when it comes to all of the various .NET Framework classes and methods available. In the past, when you've needed to search for all the members of a particular group (using the 'member' attribute) or all of the members of a particular address list (using the 'showInAddressBook' attribute), those particular searches could be very slow and quite inefficient.

With the Windows Server 2003 Domain Functional Level, the ASQ capability becomes available. Using a DirectorySearcher object, you can specify a particular group or a particular address book or (anything else that leads to a multi-valued attribute) and execute an efficient search against the sources to find their components. In this example, you can easily find the members of the 'Domain Admins' group in your domain (note, this is an easy one - there are others that are likely more significant for you).

$group  = New-Object System.DirectoryServices.DirectoryEntry( `
    "LDAP://CN=Domain Admins,CN=Users,DC=essential,DC=local")
$source = New-Object System.DirectoryServices.DirectorySearcher

$source.SearchRoot  = $group
$source.SearchScope = [System.DirectoryServices.SearchScope]::Base
$source.Filter      = "(objectClass=*)"

$source.PropertiesToLoad.Add("member")
$source.PropertiesToLoad.Add("sAMAccountName")

$source.AttributeScopeQuery = "member"

$results = $source.FindAll()

$results

One caveat: when searching for members of a group, ASQ does not work for the primaryGroup! So if you do a search for "Domain Users", it is likely that you will receive no responses in your result. This is NOT an error.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | with no comments
Filed under: ,

I've brought up a number of new clients on Exchange 2007 recently, and a common issue is this event log warning:

Event Type:      Warning
Event Source:    MSExchangeIS Mailbox Store
Event Category:  General 
Event ID:        1025
Date:            7/18/2008
Time:            10:26:40 AM
User:            N/A
Computer:        EXCHANGE
Description:
An error occurred on database "StorageGroup\Database".
 Function name or description of problem: Restrict/SetSearchCriteria
Error: 1162 Warning: fail to apply search optimization to folder (FID 4-3DBEABE)   Retrying without optimization. 

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

If you spend time on Internet search engines, you'll find lots of bad advice about running an Isinteg to eliminate these, or running an offline defragmentation to get rid of these. At best, those are temporary solutions. I finally had seen so many of these, I asked Microsoft about them. Here is the answer from the horse's mouth:

You have an application that is trying to perform a search using restrictions against a users search folders and this could be a time based query, etc.We will do two types of searches (1 fast optimized search if the indexes are there, 1 slow find) which takes a long time and will chew up processor time for store if your user has a ton of items in their folders (more than 5,000 items per folder). This is just telling you that we are performing an un-optimized search against that table in the store. They cannot be suppressed.

In other words, ignore them. You may have users that have far too many items in their primary folders (Calendar, Tasks, Inbox, Sent Items, Deleted Items) and you can get rid of these messages if you get them to clean those up. But it may not be worth your time and energy.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | with no comments
Filed under:

In 2004, I wrote an article Why Can't I Have Outlook and Exchange on the same Computer? It applied to versions of Exchange prior to Exchange Server 2007. When written, E12 (Exchange 2007) was still quite early in development at MSFT...

Today, times and situations have changed.

With Exchange Server 2007, in fact, the export-mailbox command is only supported on 32-bit machines. This means that you must run export-mailbox on a 32-bit Vista or XP computer where the Exchange Management Tools have been installed, along with Outlook! Amazing.

And, in fact, there are times where Outlook (or the CDO/MAPI binaries) will be required to be executed on an Exchange server to get certain tools to work, including OABinteg and MFCmapi.

Prior to Exchange Server 2007, installing Outlook on an Exchange Server would replace certain DLLs that Exchange required with stub libraries that Outlook used instead. This could break Exchange severely.

Those problem DLLs are gone in Exchange Server 2007. This gives us clear sailing for Outlook and Exchange on the same computer - both servers and workstations.

Thanks to Dave Goldman and Ben Winzenz, both of Microsoft, for answering my questions on this topic.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | 3 comment(s)
Filed under: ,

Almost everyone has, at one time or another, wished that you could have multiple copies of Outlook running at the same time. After all, opening another mailbox within Outlook doesn't give you windows toast and calendar pops, etc.

The standard answer has always been "run Outlook for your primary mailbox and use OWA for all the other mailboxes", which works; but well, OWA just isn't Outlook.

That's still the official answer.

However, early this year a hacker known as "H.O.G." (for HammerOfGod) released a tool known as ExtraOutlook! This tool actually modifies the Outlook executable and causes Outlook to NOT check to see if another Outlook is running.

If you are "plug-in free", this is a great tool and it works really well.

However, it confuses quite a number of plugins (such as Xonbi) that attempt to open a "default MAPI profile" and find two (or more) running instead of just one.

I'm sure that modifying the Outlook executable puts you straight in the "not supported" arena as well. But if you need the tool - you probably don't care.  :-)

Give it a go. No promises, but it has worked for me.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | 2 comment(s)
Filed under:

I was recently (ok, this morning) trying to find out about a vbscript (actually WMI) error that I was getting, with little success. However, in doing so, I found this forum posting: http://www.tutorials-win.com/WindowsServer/Services-Windows/

This irritates me a great deal. Matheiu Chateau, whoever he is, has taken one of my scripts and taken the credit for it.

I originally published that script in 2006, in my blog posting Finding Services Using non-System Accounts. I am MORE than happy that people use it. And I'm MORE than happy that other people recommend it. But doing so without giving proper credit is just wrong. If I could've located an e-mail address for him, I would've written him a scathing e-mail.

grrr....

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | with no comments
Filed under:

I don't often just link to another blog posting for MY blog posting, but this one deserves it. It's not new, but last year fellow Exchange MVP Glen Scales wrote a script which allows you to export large mailboxes to ANSI PSTs.

It does this by copying each item in a source mailbox to a destination PST; when the destination PST is too big (i.e., 1.8 GB in size) the PST is closed and a new one opened. So a mailbox of 10 GB would take 6 PSTs to dump.

In the past, the only real way to handle this with ANSI PSTs was to manually configure a date range for archiving, or selectively export specific folders. This is a real win!

So, see Glen's post: Exporting a mailbox larger then 2 GB and spanning it across multiple PST files with a script.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | 1 comment(s)
Filed under: , ,

On Exchange Server 2007, especially post service pack 1 (I ran into this problem while installing service pack 1 update rollup 2), it appears that some of the assemblies (that is, parts of the various Exchange programs) are "signed with Authenticode". This is basically a public/private key infrastructure (PKI) supported by Microsoft to allow people to verify that the various Exchange programs have not been tampered with.

At this moment, you are either thinking "So what?" or "Sounds like a good idea."

Personally, I'm in the "sounds like a good idea" camp. But I'm not sure that the concept is fully baked.

Consider this: part of any PKI infrastructure is a way to indicated when a particular key is no longer valid. Without going into too many PKI details, a key is normally called a "certificate" and the way you check the validity of a key is by seeing if the key is on a CRL - a certificate revocation list.

The first time a managed and signed assembly loads, Windows Server needs to check and see whether the key (certificate) the assembly is signed with is valid. How does it do that? By checking the CRL - at Microsoft. Specifically, at http://crl.microsoft.com/pki/crl/products/CSPCA.crl.

Even if you are in the "sounds like a good idea" camp, you may be asking "what's wrong with that"?

So I'll tell you - many environments do not allow their mailbox servers to talk to the internet (just to the hubs and to clients on specific networks). Many environments do not allow their hub transport servers to talk to the Internet (just to the mailbox and client access and e-mail gateway servers). Etc. etc. In fact, controlling and minimizing access using IPSec to specific servers has long been considered a best practice.

But it won't work with Exchange Server 2007 any more. When installing rollup 2 on a mailbox server, the "Microsoft Exchange Service Host" will fail to start. It will simply time out. No error messages. No log messages. No nothing.

I suspect that it could be any Exchange service that has this problem. This was just the one I happened to run into.

Debugging this was painful. Eventually, after a couple of hours, you do a "netstat -an" and say WTF???!!! in regards to a SYN-SENT to crl.microsoft.com and then you can start backtracking. This is not really documented directly (that is, that an Exchange server has to be able to access the Internet), but there is some information in KB 944752.

You may also find that if you are using a non-NAT proxy that this doesn't work for you. More on that in my next blog post.

Bottom line: after installing patches on your Exchange server, your Exchange server will have to "check in at home" before those patches can start running and you'll have to enable Internet access for that to happen. After they've "checked in", you can disable Internet access again.

What a management nightmare.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Update on June 19, 2008; for those folks who want for at least some of their Exchange servers to be fully isolated from the Internet, there is a workaround. See KB 936707. However, an easier (and apparently undocumented) workaround is to put crl.microsoft.com in your local hosts file - and point it to localhost (127.0.0.1)!

Posted by michael | 1 comment(s)
Filed under: ,

Sorry for the dead-silence this past week...between meetings and parties and certification tests and working and talking....it was a busy time at Tech-Ed.

(One of my editors is peeved at me - I missed a chapter deadline too!) :-(

So, I'm just going to ramble on here for a bit...

Lots of folks say that Orlando in June is just "too hot". I guess that depends on where you are coming from. I flew down from virginia, and I think that it was cooler in Orlando than it was in Virginia - of course, Virginia was going through a "heat wave". But I found Orlando quite comfortable for the entire week.

However - when I was doing my daily run (ok, it's a jog - I about three and a half miles a day and it takes me 45 minutes - you can figure out that I'm slow!) - there is no question that the humidity was higher. I always sweat - but not quite so much as I did there!

On Monday night, I met with an editor from O'Reilly Media plus a whole bunch of Active Directory folks - collectively "Team A/D" for O'Reilly (those that were present at Tech-Ed anyway). I'm doing tech.review on a couple of A/D books these days. There were some old faces and some new faces - a really good time with a bunch of geeks. Speaking of geeks - expect to hear about GEEC '09 this week from those fine folks at NetPro who bring you DEC (Directory Experts Conference).

Tech-Ed itself ran Tuesday through Friday. I won't bore you with what you've probably already read elsewhere.

But, as expected, Windows 2008 was big news, IIS 7.0, and SQL 2008. Nothing surprising there. Hyper-V of course.

I spent a lot of time talking about deployments, upgrades, and migrations with lots of customers. I think the message behind read-only DCs and server-core has confused a bunch of folks; as has the "story" behind Hyper-V. Many people thought that with server-core coming that they HAD to use it. And lots of folks didn't understand that server-core doesn't support the .NET Framework (and thus it doesn't support PowerShell or the .NET extensions to IIS 7.0!).

Most folks also didn't understand that Hyper-V doesn't do much by itself - it takes an OS to layer on top of it. oh! And NT 4.0 is NOT supported on Hyper-V. That doesn't mean it doesn't work - but it isn't supported (ok ok - NT 4 isn't officially supported anyway - but this means that the Hyper-V folks have not "qualified" NT 4.0 to work properly on Hyper-V - if you want that, you have to stay with Virtual Server 2005).

During one of my talks about upgrade/migration, I went through the entire set of domain functional levels, forest functional levels, Exchange functional levels, and how Outlook functionality was impacted. My head hurt by the time I was done with that talk. It is downright confusing by this point.

I was able to meet and talk with the folks from AppAssure, who have a killer product in their Replay for Exchange. I hope to talk more about that in the future.

I met with the VP from Wiley/Sybex who signed me up for the book I'm working on right now. Unfortunately, I was never able to connect with my current editor for the book. :-(

I also had the fine fortune to be able to meet with Tony Davis of the Simple-Talk online journal. I hope to be able to start doing some work with him soon.

Unfortunately, I didn't get to meet with any of my contacts with Penton Media (the Windows IT Pro/Outlook IT Pro) folks, and Diane from EMO wasn't able to come to Tech-Ed this year.

There were lots of new products and lots of old products. I was shocked to see Syncsort. For no reason whatsoever, really. I can just remember using them in my mainframe days, over 20 years ago....they are still alive and well. I didn't know they had made the transition to client/server.

I took six certification tests while I was there. They offer Tech-Ed attendees a discount for taking tests onsite: $50 per test. So instead of $750 for those tests, I only paid $300. I wasn't able to schedule the final one I need: 70-620 (Vista) because of scheduling conflicts but once I take that one (week after next, I think), I'll also finish up the two Windows Server 2008 MCITP certifications. I'm already "MCITP: Enterprise Messaging Administrator", those two will add "MCITP: Enterprise Administrator" and "MCITP: Server Administrator".

I'm looking forward to the class-work for the Microsoft Certified Master programs. I hope they will fit in the budget of a self-employed consultant! (Check here if you haven't heard about the Master's programs: http://www.microsoft.com/learning/mcp/master/products/default.mspx#EZ).

After the conference I hung around Orlando for a couple of extra days just to relax. It was a good time. I look forward to it next year.

Enough rambling for today. I best go try to bill a few hours tonight to help pay for this trip!

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | with no comments
Filed under: ,

Later this afternoon I'll be hopping in my car and heading for the airport to travel to Orlando for Tech-Ed 2008 IT Pro.

I'll be part of "ask the experts". I signed up for Exchange and PowerShell - somehow I ended up in Server 2008??!!

Come by and say "hi"!

Posted by michael | with no comments

One of the mailing lists I read and occaisionally post on is named ActiveDir. A lot of heavy-hitters in the AD world hang-out around there. I've learned quite a bit by lurking there.

A recent poster had wanted to create a few thousand accounts for testing purposes, and have them all follow a certain format for the samaccountname, the mailnickname, and the e-mail address. That's tough to do with the standard tools (if you are on Exchange 2007, with "new-mailuser" this can be done in a couple of lines of PowerShell, but the poster was on Exchange 2000).

Joe Richards ('joe'), author of admod and adfind (two truly invaluable tools - if you don't have them, get them), said that his admod tool was perfect for this, and offered up the following command line (you'll have to scroll to the right to see it all):

admod -add -autobase 40:cn=Test,ou=test,dc=eng,dc=myco,dc=com -counterstart 23001 -bmod cn={{*cnt*}}_{{*name*}},{{*parent*}} -expand -csv -kerbenc samaccountname::{{*cnt*}}_{{*name*}} mailnickname::{{*cnt*}}_{{*name*}} unicodepwd::MyPassword1! objectclass::user useraccountcontrol::512 msExchHomeServerName::"::"/o=Org/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=mail1"

So the basic assumption here is that 40 users are going to be created in a particular OU. The name of the users are going to be of the format 230xx_Test, the accounts are going to be enabled, have a password set, have a mailnickname set, and a particular Exchange server set.

(By the way - setting mailnickname and msExchHomeServerName will cause RUS to stamp a user object on Exchange 2000 and Exchange 2003. It's not documented. SSSssshhhhh.)

What can you say? That's an amazing command line. But in his post, joe made a negative comment about PowerShell, so I had to respond. (Completely friendly rivalry there...)

Here is PowerShell code to do the same thing. As I shared in my response post - it's a few lines longer, but much easier to read!!! (If you wanted to do it all on one line - you could - but it would be impossible to read.)

function createUsers([string]$base,[string]$userPrefix,[string]$userSuffix,[string]$homeServer,[string]$password,[int]$baseCount,[int]$count)
{
	$objBase = [adsi]('LDAP://' + $base)
	[int]$top = $baseCount + $count
	for ([int]$i = $baseCount; $i -lt $top; $i++)
	{
		[string]$user = $userPrefix + $i.ToString() + $userSuffix
		$objUser = $objBase.Create("user", "cn=" + $user)
		$objUser.Put("sAMAccountName",       $user)
		$objUser.Put("mailNickName",         $user)
		$objUser.Put("msExchHomeServerName", $homeServer)
		$objUser.SetInfo()
		$objUser.psbase.Invoke("SetPassword",           $password)
		$objUser.psbase.InvokeSet("useraccountcontrol", 512)
		$objUser.psbase.CommitChanges()
	}
	$objBase = $null
}

createUsers 'ou=OUtest,dc=essential,dc=local' '' '_Test' `
	'/o=First Organization/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=WIN2003-EXCH' `
	'MyPassword1!' 23001 4

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Exchange has caught a lot of crap for publishing the fact that it doesn't work in branch office locations where only Windows Server 2008 read-only domain controllers (RODCs) are available. Exchange simply requires read-write domain controllers. It's a fact.

However, it's been a poorly kept secret that Windows XP and Windows Server 2003 don't work well either in branch locations with only RODCs. You have needed Vista or Windows Server 2008 in those locations for all things to be happy.

Until now: Description of the Windows Server 2008 read-only domain controller compatibility pack for Windows Server 2003 clients and for Windows XP clients. KB 944043 fixes many of the issues with Windows XP (service pack 2 or service pack 3 only) and Windows Server 2003 (service pack 1 and service pack 2).

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | with no comments

If you want to write client applications to run on computers that use MAPI or CDO (for example, web servers) and you don't want to install (or can't install) either the Outlook client or the Exchange management tools, then you need to install the MAPI/CDO libraries.

These were released just last week for Windows Server 2008 and Windows Vista. You can get them here.

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | with no comments
Filed under: ,

We consultants help each other out, of course. I know Exchange and Active Directory pretty well, but put me in front of Citrix or a big T/S farm or a PKI implementation - heck, I'll scream for help without any qualms whatsoever.

So, a consultant I share favors with called me this week - quite perplexed.

He was working at a company and they were working on a hardware migration - Exchange Server 2003 to Exchange Server 2003. They had a 50 GB store and a few hundred mailboxes.

This company had an onsite junior technician who wanted to help out, so my comrade-in-arms had given this junior tech a list of things to do, in order to prepare for the migration. Off the junior tech went to do them...

...and he came back and said "all done, but would you move the mailboxes? I don't feel comfortable with that...."

So....a couple hundred mailboxes moved later, and no more mailboxes would move. <scratch head>

Outlook connects, but no e-mail is being delivered to or from those folks who have been moved. <scratch head some more>

<investigate, investigate, investigate>

<give up>

<IM Michael on MSN Messenger...hey dude....>

So I remote in, and five minutes later, I'm laughing so hard I almost split a gut.

The instructions my friend had given the junior tech. included how to install Exchange Enterprise and to install service pack 2.

Well, the junior tech. couldn't find the media for service pack 2. So, almost correctly, the junior tech. assumed he could just install Exchange Standard and set the registry key so that it would support a larger mailbox store.

So that's what he did. A perfectly good Exchange Standard install and he set the "Database Size Limit in Gb" to 75 - no problem for a 50 GB store.

BUT....(you knew this was coming, right?)

....wait for it....

he forgot to install service pack 2

So the store would mount...say oops! too big....dismount.

Lather, rinse, repeat.

The moral of the story? Well, I guess there are a couple:

1) Trust...but verify - ensure that what you think was done was actually done. Like Gregory House says, "People always lie." I would add - even when they don't mean to (it isn't always malicious).

2) Use your Event log. If it is telling you things that don't make sense - see moral 1. Occam's Razor almost always applies.

3) It's ok to ask your friends for help. :-)

Until next time...

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Posted by michael | 1 comment(s)

Over three years ago, a  particular publisher in the computer field contracted me to write a book - which I did. They paid me for it, but they chose to never publish it. It was written with Exchange Server 2003 service pack 1 in mind - as you read the text, keep in mind that it was written long before E12/Exchange 2007 was even in beta. Here is a chapter from that book. These scripts will usually work with Exchange Server 2007 - except when they use CDO, CDOEX, or CDOEXM.

It's taken me over a week to translate this from Word 2003 to web format. It's not as easy to do as I thought!

You can find some earlier versions of these scripts already on the blog. The ones in this chapter tend to be a bit better implemented and debugged.

Enjoy!

Chapter 12

Scripting Tasks 

Scripting is not magic. It is the application of a logical thought process to a problem. If you can describe the problem, there is probably a way to script a solution. However, scripting is not a panacea. It is best used for relatively discrete, often small repetitive tasks where high performance is not a key design metric. To implement a full application with scripting is challenging and supporting large scripts can also be somewhat difficult, as script-based development environments aren’t generally as rich as those for more complex languages.

 

There are, unfortunately, things that just can’t be done in a script because Microsoft hasn’t provided interfaces to do so. But those are getting fewer and fewer with every service pack and release of software. One of the key omissions in the Windows Scripting Host is that there is no way to build GUIs without using IE (which is just a little bit difficult).

I am going to show you some tools that I use, based on VBScript, that were developed by leveraging reusable components. A reusable component only has to be developed once. The name “reusable component” is just a fancy way of saying “a small piece of a program”. If properly designed, then this small program can then be plugged in to a larger program and used many times by many different programs. My philosophy of programming has always been “be lazyonly do the job once”. Some people, including myself, would refer to this as "being efficient".

The concept of building programs with reusable components is not the same as the concept of these programs being “recipes” that you have to “cook up” to be worthwhile for your environment. For the most part, I’ve tried to ensure that they are useful to you, in and of themselves. To do that, the scripts tend to be a little bit longer than a recipe-type script might be. Don’t let that scare you offjust dive right in and go for it!

I choose to develop in VBScript, with an occasional foray into JavaScript, because the Windows Scripting Host (WSH) that includes those two languages has been built into every Windows operating system since Windows 2000. It is also available for download and installation into Windows NT 4.0 and Windows 98 (I hope you don’t run into those in your environmentbut just in case you do, the download is at http://www.microsoft.com/downloads/details.aspx?FamilyID=0a8a18f6-249c-4a72-bfcf-fc6af26dc390&DisplayLang=en). Jscript is the name of the Microsoft implementation of JavaScript. Jscript is a fairly complete language, and can be somewhat challenging to use, as a beginner. VBScript is syntactically very similar to Visual Basic, and is about as easy to learn as Visual Basic. VBScript has some limitations, but because it is so easy to learn, is used in many places.

The mere fact that the VBScript and JavaScript languages are included in every modern version of the Windows operating system makes them, in my mind, the tools of choice. Add to that, Internet Explorer will allow these languages to be embedded into web pages for client control, and Internet Information Server (IIS) will interpret these languages on the server for server controlwell, they win hands down (granted, JavaScript and ECMA Script are standards and Apache has an ASP modulebut those are add-ons and not part of the base products). There are many proponents of the cross-platform languages Perl and Python, which have a large number of modules enabling them to interface quite well with Windows. However, they require a separate install on every workstation and server that will use them and interfacing them with IIS requires a number of extra steps. On the other hand, they are fully developed languages with greater capabilities than those present in VBScript and JavaScript, with a correspondingly larger resource footprint.

There is a comprehensive reference guide available for both VBScript and JavaScript at http://microsoft.com/scripting, along with a huge library of code samples and the truly excellent ScriptOMatic, which can help you generate scripts of almost any type. An excellent book is VBScript in a Nutshell, Second Edition by Paul Lomax, et al (O’Reilly Media).

The Microsoft Scripting Host (MSH), code-named Monad, will be the replacement for WSH. It is currently in beta. Support for Monad will be built into Exchange 12 and it is planned to come as an add-on to Windows Vista and Windows code-named Longhorn. However, even when Monad is released, older scripts should continue. New features may require use of Monad, but all features should continue to work for quite some time.

Each of the scripts found in this chapter can be found at the author’s home page: http://www.msmithhome.com/.

The permissions model for these scripts is tied directly to required permissions for Active Directory and Exchange Server. In general, any script which only uses ADSI for interrogating Active Directory may be executed by any “Authenticated User” in Active Directory. Any script which uses ADSI to update objects will require Domain Admin permission in Active Directory (or appropriate delegated permission). Any script which uses CDOEXM (and there are only a couple of those) minimally requires Exchange View Only Administrator for reading Exchange information and minimally requires Exchange Administrator for updating Exchange information.

Understanding WSH

You will not learn everything you need to know on how to author scripts in this chapter, but you will learn something of my philosophy of writing scripts and some key points important to scripting.

I used the phrase “reusable components” in the preceding section. In WSH, this translates to a file that is included (that is, read by the command interpreter and inserted into the program at the position where the include instruction is located) into your script. Normally, a VBScript has a file extension of VBS and a JavaScript has a file extension of JS (please note that there are certainly other extensions recognized by WSH for those filesanother set of common extensions is VBE and JSE). Any file having either of those file extensions is considered an executable by the Windows command processor. In order to use the include-file capability, your script must end with the file extension WSFWindows Script File. An interesting side benefit of WSH is that it is very modular. It is possible to include multiple files into a WSF, and in fact, these files can be in different languages. It is completely possible to have multiple separate routines, in a single script, written in VBScript and JavaScript (plus any other language modules you may have installed). This is most useful when you have a bit of code written in one language that you don’t wish to rewrite, or when you need to use a feature of one language that isn’t present in the other (such as JavaScript’s sorting capabilities, which are not present in VBScript). Because WSH is a command interpreter, it executes commands as it sees them. On the positive side, this allows you to initialize variables when and where they are declared. On the negative side, this allows you to author very messy scripts that are difficult to support once written. Both JavaScript and VBScript really only have a single type of variable, called a variant. Each variant type will have a number of characteristics depending on the data stored in the variant. A single variable can be an object, a string, a floating point number, or an array; all in a single program. This sounds complicated, but it actually isn’t. The command processors automatically “coerce” (i.e. change) the variable as needed, whenever possible. When this can’t be done, an error will be generated. An object is composed of properties and methods (when I was in school in the Stone Age, this was said this way: “an entity is composed of attributes and actions”the more things change, the more they are the same). A property is a piece of data. That piece of data may be a simple variable (such as a number, a string, etc.), it may be a collection (such as an array), or it may be another object. A property can be read-only, read-write, or write-only. A method is a way of acting on that object (or some piece of the object); such as creating a object, deleting an object, etc. The important thing about objects is that they are usually specifically created with CreateObject() and that you access a property or method by separating the name of the object from the property or method with a period (for example, someobj.Update).

Exchange Scripting Technologies

As Exchange Server has grown and matured as a product, the various tools available for modifying Exchange and its objects have grown and matured as well. These technologies include:

CDOCollaboration Data Objects
In the beginning, there was CDO… CDO was the first of the exposed messaging interfaces and it was much simpler to use than MAPI (although it was based on MAPI). And the capabilities were pretty limited. It was primarily good for sending email via an Exchange server. CDO also includes various incarnations known as CDONTS and CDOSYS, which are included with Windows NT 4.0 Server and above, which support the sending of SMTP email without using Exchange Server.

CDOEXCDO for Exchange
CDO for Exchange is an enhanced version of CDO which is available only on an Exchange server. CDOEX includes support for other Exchange objects such as folders, appointments, calendars, tasks, contacts, mailboxes, etc. Using CDOEX, you can build complete messaging applications.

CDOWFCDO for Workflow
Initially, Exchange Server was positioned by Microsoft as a “Lotus Notes” killer, and the work flow capabilities of Exchange were strongly pushed. CDOWF provided the work flow support in Exchange, supporting event driven work flows (e.g. if “A” happens then do “B”). CDOWF never caught on, for various reasons. As of Exchange Server 2003, CDOWF has been turned into a legacy feature (no new development, but still supported). The capabilities present in CDOWF have been absorbed and significantly expanded upon by Windows SharePoint Services.

CDOEXMCDO for Exchange Management
CDOEXM provides the capabilities for managing the Exchange systemdealing with servers, storage groups, message stores, public folder trees, etc. Each of these objects can be manipulated in various ways, such as creating, deleting, mounting, moving, etc. CDOEXM is limited in the objects it handles (it does not allow you to modify or create Address Lists or Recipient Policies for example) and a program or script using CDOEXM can only be run on a server where Exchange Server is installed or a computer where the Exchange System Management Tools are installed. Some information (particularly some message store related information) can only be accessed via CDOEXM, and not via other technologies.

ADSI—Active Directory Service Interfaces
Not a uniquely Exchange scripting technology, ADSI provides the interfaces into Active Directory. Most of the capabilities of CDOEX and CDOEXM can be replaced with ADSI scripts. Doing so has the advantage of allowing the scripts to run on computers which do not have either Exchange Server or the Exchange Server System Management Tools installed on them. Most of the scripts shown in this chapter will use ADSI.

ADOActiveX Data Objects
These components provide capabilities for accessing data from multiple places through a common interface. Both Active Directory and Exchange Server support ADO.

WMIWindows Management Instrumentation
WMI is the Microsoft implementation of WBEM (Web-Based Enterprise Management). Got that? WMI is simply a way for information to be presented, interrogated, and modified in an industry standard way. Both Exchange Server and Active Directory expose a large amount of their data via WMI. With Exchange Server 2003, WMI provides more access to more information than any other interface.

MonadMicrosoft Scripting Host (MSH)
Monad is currently beta technology. However, it has been announced that Monad will contain all the capabilities of the above technologies and more. E12 (which is the codename for the version of Exchange following Exchange Server 2003) will have its ESM written based on Monad commands and routines. Therefore, all the capabilities of ESM will be available to third-party developers and administrative script writers. With this information, you are now prepared to see some scripts.

Reusable Components

I have developed these scripts (as indeed, I develop most of my scripts) using include files that contain some routines that I use over and over again. Doing this has a number of advantages:

·         It lets me be lazy, since I only have to develop a piece of code once.
·         It eases upgrades. If I were to find a bug (heaven forbid!) I only have to fix it in one place
·         It speeds development. If a piece of code is already written, I don’t have to rewrite it.
·         It lets me forget. I don’t have to remember an arcane programming detail—I already figured it out once, I’ll just use it again.

As you probably can see, the last three reasons are really just corollaries of the first reason. Are there downsides? Sure. If you are a programmer coming in to maintain someone else’s script or program that uses reusable components, you are going to have to investigate more thoroughly to ensure that you understand their “shorthand”. You also may need to copy more than a single file to another computer when moving scripts to another computer.

constants.vbs

The initial file I always have in a script development project is a file which contains all of my constants and pseudo-constants. These are values that either never change or probably won’t change, but may under special circumstances in a program. In VBScript, I call this constants.vbs. Here is the file used in the scripts in this book:

' Constants we need for ADSI calls
Const ADS_PROPERTY_CLEAR = 1
Const ADS_PROPERTY_APPEND = 3
Const ADS_PROPERTY_DELETE = 4 
' Constants we need for WBEM calls
Const wbemFlagReturnImmediately = &H10
Const wbemFlagForwardOnly = &H20 
' Constants we need for configuration 
' the exchange server whose default mailbox store I'll use
Const ExchServer = "SERVER" 
' Are we a web application or not?
Const bWebApplication = False 
Dim bDebug               
' verbose output (pseudo-constant)
bDebug = False

From this listing, you can determine that you’ll be seeing scripts containing modifications to Active Directory properties and that you’ll make some WMI calls. In order to run these scripts in your environment, you’ll need to specify the flat (NetBIOS) name of an Exchange server in your environment in the ExchServer constant. Only one script has the requirement of being run on an Exchange server.

With very little modification, you could take most of these scripts and put them into a web-based application (using HTA or ASP files). I do that on a regular basis. There are a couple of things that need to be modified for this, and several of the included scripts detect this and modify their code based on the setting of the bWebApplication constant. Finally, the bDebug variable is usually set to false. However, in some places I explicitly will choose to set it true, in order to allow you to see the additional output generated by some of the debugging code in a couple of the scripts. Since constants are, well, constant; you could not modify the value of bDebug if it were a constant.

ado.vbs

My next component, which is included in scripts that access Active Directory, is ado.vbs. This include file has the routines that make it easy to use ADO with Active Directory, without remembering lots of stuff you don’t normally need to know. Some would argue that remembering all of those things is worthwhile, and I guess if ADO programming was my focus, I would tend to agree. However, extracting information easily from Active Directory about Exchange is my focusnot ADO.The include file begins with the declaration of “global variables”. That is, variables which will be modified by the routines in this file and are available for visibility outside of the include file.Just a little background: ADO works by a script having a connection to a provider. In this case, the provider is Active Directory (there are many others). In order to do something with that connection, you will need a command. And that command produces a result, once it is executed. The result may contain zero or more rows of data (just like a row in an Excel spreadsheet). Therefore, our global variables are as follows:

Dim objCom    ' the global ADO command object
Dim objConn   ' the global ADO connection object
Dim Rs        ' the global ADO resultset object

You will notice that my naming conventions tend to be somewhat descriptive. Usually, I begin the name of a variable with a one-to-four character description of the type of the variable, such as “obj”, which stands for “object”. This is followed by the proper name of the variable, which I always capitalize. However, for certain oft-typed variables I will, at times, forego the type description. The naming convention that I use is a common one. It helps you remember the type of a variable you are dealing with, as well as what the variable is being used for.
I often use more lines than the language requires. This allows me to insert comments into my scripts. Comments help both me, and people that use my scripts, and those that modify them down the line, to figure out what it was that I was doing. Even though some things may have been “obvious” to me, that doesn’t necessarily mean that they are obvious to someone else. Without comments, the declarations above could have been written as:

Dim objCom, objConn, Rs

However, that would’ve left you with much less information about what the variables are intended to be used for.
After the variables are declared, I begin the declaration of the subroutines and functions. The primary difference between a subroutine and a function is that a function will return some value. Just like other variables in VBScript and JavaScript, the functions return a variant type, which may be coerced into just about any type. JavaScript doesn’t support subroutines which do not return a value, all routines are functions. However, the script writer may choose to ignore the value of a function (which is true for VBScript as well).The first subroutine you encounter is:

Sub InitializeADSI
    Set objCom  = CreateObject ("ADODB.Command")
    Set objConn = CreateObject ("ADODB.Connection")
 
    ' Open the connection.
    objConn.Provider = "ADsDSOObject"
    objConn.Open "ADs Provider"
End Sub

There are several things to note about this short subroutine. First is the keyword “Sub” which indicates that a subroutine is beginning. If this was a function, the keyword would be “Function”.
I always “properly” capitalize keywords (capitalize the first letter and make the other letters of the word lower-case) in VBScript, but the script interpreter doesn’t care. There is no case-sensitivity in VBScript. However, JavaScript is case-sensitive. All keywords are in lower case, and a declaration of “var i;” is a different variable than a declaration of “var I;”.Next is the creation of two new objects, via the keyword CreateObject. This keyword attempts to call an ActiveX control (which has been previously registered on the computer) and create the object specified. Note also use of the “Set” keyword to assign a value to an object (normal assignments in VBScript have an implied “Let” keyword, which is derived from the very beginnings of the BASIC language).If either of these creations fails, an error message will be displayed on the user’s computer and the script will terminate. However, failures of these creations are unlikely and there truly is no recourse. If both succeed (almost certainly), then the provider for the connection is specified, and the connection is opened.Next up, the opposite of InitializeADSI is DoneWithADSI, as follows:

Sub DoneWithADSI
    objConn.Close
 
    Set objCom  = Nothing
    Set objConn = Nothing
End Sub

In this subroutine, the connection object previously opened is now closed. Also, the objects created are “cleaned up”. 
The keyword Nothing indicates to VBScript that if there is memory associated with an object or cleanup to be done, that it should be done now.  If this isn’t executed explicitly by the script, it is automatically done by VBScript when a script terminates. However, it is simply a good programming practice to clean up after yourself. This is not necessary for simple variables, only for objects. Setting the value of the variable to Nothing also allows the variable to be re-used somewhere else in the script as a different variable type. Finally, because objConn is treated as an object in this subroutine (via the call on the method objConn.Close), this routine will fail if the InitializeADSI subroutine was never called.Next, you have the definition for the subroutine that actually makes the ADO calls for you:

Sub DoLDAPQuery (strLDAPQuery, resultSet)
    dp "LDAP query: " & strLDAPQuery
 
    objCom.ActiveConnection         = objConn
    objCom.Properties ("Page Size") = 1000
    objCom.CommandText              = strLDAPQuery
 
    Set resultSet = objCom.Execute
End Sub

There are a number of new items to be explained in this subroutine. First, you see the first sample of parameters. There are two parameters,
strLDAPQuery and resultSet. These are variables which can be used to pass information into a subroutine or function as well as be changed by the routine to send information back out of the subroutine or function. In this case, the first parameter strLDAPQuery is used to pass the command to be executed by the connection created in InitializeADSI and resultSet will contain the results of the command.
However, the first line of the subroutine is a call to another subroutine (dp) that has not yet been declared. You’ll see more about that routine in the reports.vbs include file. In this routine, you see the setting of a named parameter called Page Size. Normally, ADO (actually, it is the LDAP engine in Windows Server) will return only the first 1,000 results.  Setting the Page Size attribute causes all results to be returned in batches of the specified Page Size.Finally, you see the resultSet variable being assigned to objCom.Execute. This causes the Execute method of objCom to be called, which processes the command stored in the CommandText attribute of objCom via the connection stored in the ActiveConnection attribute. Is that clear as mud?Suffice it to say that when DoLDAPQuery returns, resultSet contains the results of the command in strLDAPQuery.The final subroutine in ado.vbs is:

Sub FinishLDAPQuery (resultSet)
    resultSet.Close