Exchange Management Shell (EMS) in Microsoft Exchange Server 2007 lets you set properties on objects to manage every aspect of your Exchange environment. The -confirm and -WhatIf switches are built-in safety features that help prevent accidental loss of data. Any property that appears in a Set-* cmdlet should be available in the corresponding
Get-* cmdlet, and you can view the list of supported properties from the output of the Get-* cmdlet. EMS also lets you set data types specific to Windows PowerShell and set multivalued properties.
There’s a lot more to Microsoft Exchange Server management than just looking at things. In the first two parts of this series on using Exchange Management Shell (EMS), we’ve discussed the basics of how Exchange 2007 uses Windows PowerShell, and how you use EMS to retrieve Exchange objects and inspect their properties. Now it's time to explore how to set properties of various types—think of this as the next step to the concepts we’ve discussed in previous articles (see "Exchange Management with EMS: Fundamental Concepts" and "Exchange Management with EMS: Getting Exchange Objects").
Saving Your Bacon in Advance
Have you noticed how Microsoft puts a stern warning in every Knowledge Base article that mentions editing the registry? Consider this paragraph to be the equivalent for EMS. Any time you make changes to your Exchange objects using EMS, you run the risk of breaking something. The EMS cmdlets are pretty robust, and they generally check to make sure that the values you’re providing as input are of the correct type and range. However, you might do lots of things accidentally, such as changing the authentication type on your Microsoft Outlook Web Access (OWA) virtual directory, that can have unexpected side effects. So you should exercise reasonable caution when making changes.
There’s good news, though: EMS includes some safety features that can help protect you against accidents. The first is the -confirm switch, which lets you instruct EMS to confirm each individual operation with you before it takes place. For example, suppose you were overcome with curiosity and decided to enter this command in your EMS window:
Get-Mailbox | Remove-Mailbox
You might be surprised to see a confirmation prompt like the one shown in Figure 1. You get this prompt because one of the Exchange team’s engineering requirements for EMS cmdlets is that any cmdlet that can cause data loss (such as, say, removing all your mailboxes) must explicitly require confirmation. The -confirm switch is turned on by default for a wide variety of commands that might otherwise cause you to lose data. However, the -confirm switch is optional for manipulating properties using most of the Set-* cmdlets. Be very careful when setting properties en masse; specify the -confirm switch explicitly whenever you’re not sure of the scope that your command will affect.
For interactive use, having the -confirm switch turned on is probably the safest approach. However, if you’re using commands such as Remove-Mailbox in a script, you might want to suppress this behavior, which you can do by passing a value of $false for the -confirm flag, as this command shows:
Remove-Mailbox "LarryEllison" -confirm:$false
Turning off the confirm flag is somewhat akin to removing the safety from your pistol so you can draw and fire it faster, so be careful with it; it’s easy to make a mistake when confirmation is disabled.
As another built-in safety feature, EMS lets you experiment to see what a command would do. This magic happens when you use the -WhatIf flag, which shows you what the results of running the command would be without actually making any changes. For example, the following command shows you what mailboxes would be removed if the command were executed, but it won’t actually remove them:
Get-Mailbox "*aux" | Remove-Mailbox -whatif
Figure 2 shows the output this command generates. You’ll typically use -WhatIf as part of the last command in a set of commands. There’s no need to use -WhatIf with a filter statement and it isn’t very useful for most of the Get-* cmdlets because they're always nondestructive. However, any time you’re removing, setting, or otherwise creating or modifying data, this flag can be a lifesaver—provided you read what it’s telling you.
Setting properties is simple, provided you know which property or properties you want to set. Let’s say that you want to set the mailbox quota for a group of users. The quota is obviously a property of the mailbox object, so your first instinct would probably be to look at the property lists for the Get-Mailbox and Set-Mailbox cmdlets to see if there are any property names that seem to address quotas. If you examine the properties shown in Microsoft's online help for Set-Mailbox, the quota properties are listed, but the online help for Get-Mailbox doesn’t show them. However, if you try piping the output of Get-Mailbox, which includes all its supported properties, to Format-List, you’ll see that the quota properties are there after all.
From these results, you can derive a general rule: Any property that appears in a Set-* cmdlet is probably available in the corresponding Get-* cmdlet. You can always get a list of supported properties by using the Get-* cmdlet and looking at the output.
Back to the example. We want to assign quotas to a group of users for when they'll receive a warning about their mailbox size, when they'll be prohibited from sending messages, and when they'll be prohibited from receiving additional messages. There are a couple of ways to select the users whose mailboxes we want to modify, depending on how they’re organized in Active Directory. Get-Mailbox supports wildcards, or we could use Get-DistributionGroupMember to expand membership of a distribution or security group. If the users are all in the same organizational unit (OU), we could even use the -OrganizationalUnit flag with Get-Mailbox to automatically fetch all the mailboxes in the OU.
The more interesting challenge is how we set the mailbox quotas themselves. The answer lies in the property list for Get-Mailbox. We need to set four properties to get the desired results:
- IssueWarningQuota is the property required to set the quota above which users get a quota warning message.
- ProhibitSendQuota is the property required to set the quota limit above which users can’t send new messages.
- ProhibitSendReceiveQuota is the property required to set the quota limit above which users can’t send or receive messages.
- UseDatabaseQuotaDefaults is the property that tells Exchange to ignore the default limits for the mailbox database in favor of the limits set directly on the mailbox.
A little experimentation shows that we can specify the quota sizes in a variety of formats: bytes, kilobytes (with the kb specifier), megabyes (with mb), or gigabytes (with gb). Giving all our users a 2GB quota is as simple as this:
Get-Mailbox -OrganizationalUnit “FullTimeEmployees” |
Set-Mailbox -IssueWarningQuota 1950MB
Note that while the code wraps here, you would enter it all as one line in EMS. Of course, the Set-* cmdlets change only the properties you specify. In the example above, none of the other mailbox properties are touched, even though they’re all passed from Get-Mailbox to Set-Mailbox. This situation is reassuring when you're performing operations that affect major Exchange objects such as OWA virtual directories or mailbox databases.
Most Exchange objects use familiar data types, such as strings and integers. Behind the scenes, PowerShell maps some of those types to its own internal types. For example, the mailbox quota limits that we enter as integers, with optional size specifiers, PowerShell treats internally as the type Microsoft.Exchange.Data.ByteQuantifiedSize, which helps explain why the error messages you get when you specify a value of the wrong type contain information about the type being incorrect.
Some objects use more complex property types. For example, if you want to set the maintenance schedule for a mailbox or public folder database, you'll find that you have to specify the days and times using a nonstandard though fairly understandable format: startDay.startTime-endDay.EndTime. The endDay part is optional if you’re specifying a time period that falls within a single day. You can string together multiple maintenance cycles; for instance, to run maintenance from 2:00 A.M. to 4:00 A.M. each Monday, Wednesday, and Friday, you'd enter this command:
Get-MailboxDatabase | Set-MailboxDatabase
-MaintenanceSchedule "Mon.2:00-4:00", "Wed 2:00-4:00", "Fri 2:00-4:00"
However, the Schedule data type, which is used for the MaintenanceSchedule parameter, includes a long list of predefined types with useful values such as DailyFrom11PMTo3AM and SundayAtMidnight. To use these values, you have to do something a bit unusual and use the @ operator along with the name of the schedule’s full data type, like this:
Set-MailboxDatabase -Id “WesternRegionUsers”
This syntax is necessary only if you want to use the enumerated types; for most operations, it’s much simpler to use the existing type support to specify parameters using the native syntax.
You might frequently need to set properties that have multiple possible values. These are called multivalued properties. For example, the EmailAddresses property of a mailbox can contain more than one SMTP or X.400 address. Working with multivalued properties is quite a bit different from working with single-valued properties because you need to be able to handle three separate cases: overwriting existing values, adding values to the existing set, and removing values from the existing set. We’ll use the Set-RecipientFilterConfig cmdlet and its BlockedRecipients property as an example.
First, if you just want to overwrite an existing multivalued property with a different set of values, you can specify the new complete list, with items separated by commas. The following command wipes out whatever blocked recipients are presently defined and replaces them with a set of two recipients:
Notice the use of the curly braces to specify that you’re setting multiple property values.
Next, if you want to add to the existing values without overwriting them, you’ll need to save a copy of the object to a new variable, modify it, then put it back. So, here’s one way to add a third blocked recipient to the previous example’s list:
$tempConfig = Get-RecipientFilterConfig
$tempConfig.BlockedRecipients += firstname.lastname@example.org
Set-RecipientFilterConfig -BlockedRecipients $tempConfig.BlockedRecipients
Whoa! There’s quite a bit of new stuff here. The first line gets the recipient filter configuration (which, remember, is an object, not just a set of properties) and assigns it to a temporary object variable. Variable names in PowerShell are always preceded by a dollar sign ($). The second line adds an email address to the existing set of blocked recipients; to do this, we use a period (.) and the property name we want to adjust, then PowerShell’s addition operator (+=). This is logically the same as writing
$tempConfig.BlockedRecipients = $tempConfig.BlockedRecipients + email@example.com
The third line makes the change permanent. We can make any changes we want to $tempConfig, but those changes won’t have any effect on actual recipient filters. If we want to apply changes, we need to use Set-RecipientFilterConfig. Because we only want to set the blocked recipient list, and not any of the other recipient filter configuration settings, we only specify the -BlockedRecipients flag to Set-RecipientFilterConfig; all other settings remain unchanged.
You can use this same technique if you want to specify multiple values to be added; just enclose them in quotes and separate them with commas, like this:
$tempConfig.BlockedRecipients += "firstname.lastname@example.org",
Finally, you might need to remove a value from a multivalued property. We use the same pattern as we did for adding a value, except we remove the desired value by subtracting it using the -= operator. However, if you need to remove multiple values from a set, you have to subtract each individual value on its own instead of specifying a set of values as you can when adding values.
The Power of Properties
Working with properties is a key part of learning to use EMS. When you understand how to get and set properties on individual objects, you’ll be able to modify the properties of any of Exchange’s objects, which gives you the ability to fully configure your Exchange environment. In the next article, I’ll talk about the difference between running commands interactively (as this article demonstrates) versus building them into scripts that you can run over and over again, and we’ll dissect some sample scripts to see what makes them work and how they’re structured.