Hosting Exchange 2007 is a difficult, tedious, and expensive venture to be certain. Taking into consideration the extensive hardware investments required, the development required to create an automated process to deploy new domains, create new mailboxes, set size and feature limitations on those mailboxes (or purchasing support for Microsoft’s HCM solution which uses the outdated MPS), and the staff required to maintain that environment makes this no venture for the weak minded (or shallow pocketed).
This is the first part in a multi-part article which attempts to cover the first part of hosting Exchange 2007…deployment…and create an inexpensive deployment solution using Microsoft’s Powershell. Based on a great article created by Rui Silva on msexchange.org, this article takes the GUI walkthrough created by Rui (which is heavy on GUI based tools such as the Exchange Management Console and ADSI) and (loosely) creates a Powershell equivalent that can be used to quickly create new fully segregated hosted domains in Exchange and new mailboxes with the required parameters and features. I have made some changes where I thought it made real-world sense (such as creating a customer ID for each customer and storing all hosted domains for that customer under their own OU).
Much of the code provided requires the Quest ActiveRoles Management Shell for Active Directory. At the time of writing this, using these predefined commands was significantly easier than using LDAP, however with the release of Server 2008 R2 and the integrated Active Directory Powershell scripting functionality, it may be better to use the native Powershell commands instead of relying on third party cmdlets.
This being part 1 of deploying a hosted exchange environment, we will focus on deploying a new hosted domain (since we cant realistically create a new mailbox for a hosted domain that doesn’t exist. The prerequisites that must be completed prior include:
Without further ado…let get started. Our first line of code is a param() command that captures the command line input (Client, which is a unique customer ID (ex. Customer1), and domain, which is the name of the domain you want to configure mail for (ex. 0direction.com)).
1 | param($client,$domain) |
The next line is the obligatory line where we load the Quest shell:
3 | add-pssnapin quest.activeroles.admanagement |
The next set of code is basically string formation such as setting the Canonical Name and the Distinguished Name, creating the SMTP template (more on this later), and setting the active Mailbox server and CAS server. We are only using one Mailbox server and CAS server, so Get-MailboxServer and Get-ClientAccessServer will only return one value and we simply set the variable to the name property.
5 6 7 8 9 10 11 12 13 14 15 | $CN = "0direction.local/Hosting/$client/$domain" $DN = "OU=$domain,OU=$client,OU=HOSTING,DC=0DIRECTION,DC=LOCAL" $GROUPDN = "CN=$domain"+"_Exchange_Group,"+$DN $SMTPTEMPLATE = "smtp:%m@"+$domain $MBSERVER = (get-mailboxserver).name $CASERVER = (get-clientaccessserver).name $DGROUPNAME = $domain + "_Exchange_Group" $AL = "\$domain" $VD = $CASERVER+"\OAB (Default Web Site)" $EXCHANGESERVICES = "CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=0direction,DC=Local" $ALC = "CN=Address Lists Container,CN=0direction,$EXCHANGESERVICES" |
After setting our string values, we use the Quest AD shell (hereafter known as QAD) to create an OU under the customer’s OU for the new hosted domain. The OU is named the same as the domain (zerodirection.com for example). We also set the UPN value on this new OU to the new domain name. Later, this will allow customers to log into the Exchange OWA using their hosted domain name as the domain instead of the default host domain (Cory@zerodirection.com instead of Cory@0direction.local).
18 19 20 | New-QADObject -ParentContainer $DN -name $domain -Type organizationalunit -Description "$domain Exchange OU" Set-QADObject "OU=$domain,OU=$client,OU=HOSTING,DC=0DIRECTION,DC=LOCAL" -ObjectAttributes @{uPNSuffixes=$domain} |
Now that the groundwork is done (The OU has been created for the new hosted domain so that we have somehwere to store our Exchange objects), we can begin configuring Exchange itself. The next batch of code does two things: it will create a “Distribution Group” which basically is an Active Directory group (after running this, you will see a new group under the hosted domain OU), and it will set the new hosted domain as an Accepted domain (this tells Exchange to accept mail for this domain).
22 23 24 | New-DistributionGroup -Name $DGROUPNAME -Type 'Security' -OrganizationalUnit $CN -SamAccountName $DGROUPNAME -Alias $DGROUPNAME New-AcceptedDomain -Name $domain -DomainName $domain -DomainType 'Authoritative' |
At this point we have a group to put new users in for this hosted domain, and Exchange knows to accept mail for it. Next, we setup an Email Address Policy (which watches the group we just created and applies an SMTP address to any user that is a member of that group), a new Address List (once again, this watches the group we just created a builds an Address List based on that group membership), an Offline Address Book (OAB), and a Global Address List (GAL).
There are a variety of ways that you can setup your SMTP template. The way I chose to go about this is by pulling the Alias value of the user account that we are creating the mailbox for and using that value to create an SMTP address (using the “smtp:%m@”+$domain, this means that the SMTP address of any mailbox created for this hosted domain will be USERALIAS@zerodirection.com).
An Offline Address Book (OAB) is an address book that is distributed to clients so that they can access the Global Address List when not connected to the internet. You can read more about deploying your OAB here. Exchange 2007 has the ability to run without public folders (as Microsoft is trying to migrate users toward Sharpoint Services), so you must make a decision of you want to deploy your OAB through Public Folders or not (depending on whether you chose to use Public Folders during your Exchange installation and if you want to expose the OAB through that venue).
26 27 28 29 30 31 32 | New-EmailAddressPolicy $domain -RecipientFilter {((Memberofgroup -eq $GROUPDN) -and (recipienttype -eq 'usermailbox'))} -enabledprimarySMTPaddresstemplate $SMTPTEMPLATE New-AddressList -name $domain -container "\" -RecipientFilter {((Memberofgroup -eq $GROUPDN) -and (recipienttype -eq 'usermailbox'))} New-OfflineAddressBook -Name $domain -Server $MBSERVER -Addresslists $AL -Publicfolderdistributionenabled $true -Virtualdirectories $VD New-GlobalAddressList -Name $domain -RecipientFilter {((Memberofgroup -eq $GROUPDN) -and (recipienttype -eq 'usermailbox'))} |
or
30 | New-OfflineAddressBook -Name $domain -Server $MBSERVER -Addresslists $AL -Publicfolderdistributionenabled $false -Virtualdirectories $VD |
The next task we must complete is removing inheritance from several AD objects and removing the “NT AUTHORITY\Authenticated Users” user from the ACL. This effectively segregates all of the objects we just created and provides a singular domain experience. If we did not do this step, when a user logged into the OWA, they would see all of the Users, Address Lists, GALs, etc that were created for other hosted domains (which we don’t want).
We accomplish this by using QAD to get all of the permissions on the object, add those permissions back to the object (which makes the permissions direct instead of inherited), remove inheritance and remove all inherited permissions (the permissions we applied in the last step will still be there), filter out all permissions for “NT AUTHORITY\Authenticated Users” and remove them from the ACL. We do this for the Address List, the GAL, the Offline Address List (OAL), and the hosted domain’s OU itself.
36 37 38 39 40 41 42 | $permissions = Get-QADPermission -Schema -Inherited "CN=$domain,CN=All Address Lists,$ALC" $permissions | Add-QADPermission "CN=$domain,CN=All Address Lists,$ALC" Set-QADObjectSecurity -Lockinheritance -Remove "CN=$domain,CN=All Address Lists,$ALC" Get-QADPermission "CN=$domain,CN=All Address Lists,$ALC" -Schema |where {$_.accountname -eq "NT AUTHORITY\Authenticated Users"}|Remove-QADPermission |
45 46 47 48 49 50 51 | $permissions = Get-QADPermission -Schema -Inherited "CN=$domain,CN=All Global Address Lists,$ALC" $permissions | Add-QADPermission "CN=$domain,CN=All Global Address Lists,$ALC" Set-QADObjectSecurity -Lockinheritance -Remove "CN=$domain,CN=All Global Address Lists,$ALC" Get-QADPermission "CN=$domain,CN=All Global Address Lists,$ALC" -Schema |where {$_.accountname -eq "NT AUTHORITY\Authenticated Users"}|Remove-QADPermission |
54 55 56 57 58 59 60 | $permissions = Get-QADPermission -Schema -Inherited "CN=$domain,CN=Offline Address Lists,$ALC" $permissions | ADD-QADPermission "CN=$domain,CN=Offline Address Lists,$ALC" Set-QADObjectSecurity -Lockinheritance -Remove "CN=$domain,CN=Offline Address Lists,$ALC" Get-QADPermission "CN=$domain,CN=Offline Address Lists,$ALC" -Schema |where {$_.accountname -eq "NT AUTHORITY\Authenticated Users"}|Remove-QADPermission |
63 64 65 66 67 68 69 | $permissions = Get-QADPermission -Schema -Inherited $DN $permissions | ADD-QADPermission $DN Set-QADObjectSecurity -Lockinheritance -Remove $DN Get-QADPermission $DN -Schema |where {$_.accountname -eq "NT AUTHORITY\Authenticated Users"}|Remove-QADPermission |
The next step in the domain provisioning process is to assign specific rights back to some of the objects we just modified. We apply GenericRead and ListChildren as well as some extended rights to the Address Lists, the GAL, and the OAL for the Distribution Group. Since all users for a single hosted domain are part of this Distribution Group, this gives all users for a hosted domain read and list rights for these Lists.
72 73 74 75 76 77 78 79 80 81 82 | $container = "CN=$domain,CN=All Address Lists,$ALC" Add-QADPermission $container -User $DGROUPNAME -AccessRights GenericRead, ListChildren -ExtendedRights Open-Address-Book $container = "CN=$domain,CN=All Global Address Lists,$ALC" Add-QADPermission $container -User $DGROUPNAME -AccessRights GenericRead, ListChildren -ExtendedRights Open-Address-Book $container = "CN=$domain,CN=Offline Address Lists,$ALC" Add-QADPermission $container -User $DGROUPNAME -AccessRights GenericRead, ListChildren -ExtendedRights ms-Exch-Download-OAB |
And last, we append the location of all of this new domains Address Books to the addressBookRoots property of the default Exchange services object “CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=0direction,DC=Local”. This allows the Address List and the OAL to show up properly for the new domain.
86 | Set-QADObject $EXCHANGESERVICES -ObjectAttributes @{addressBookRoots=@{append=@("CN=$domain,CN=All Address Lists,$ALC")}} |
That’s it! (shew…) After running this you should have a customer OU that contains an OU with the same name as the Exchange domain you wish to host. This OU contains a Distribution Group that will contain all of the user account mailboxes (that we will create in Part 2). The new domain is fully segregated with its own set of Address Lists that nobody else other than the members of this hosted domain can see! Part 2 covers mailbox creation (the next logical step), which you can find here.
Tags: exchange, Hosting, powershell
Great article – any news of part 2?
Agree with Simon, a great article and looking forward to reading the next part.
(which I have just spotted the link to!)
$container = “CN=$domain,CN=All Address Lists,$ALC”
Add-QADPermission $container -User $DGROUPNAME -AccessRights GenericRead, ListChildren -ExtendedRights Open-Address-Book
This inpunt neets an account, but i dont know wich accout it means? Could you help me out?