Microsoft Exchange Server 2007's Exchange Management Shell (EMS) includes cmdlets for retrieving all the object types and properties that Exchange supports. You can use pipelining to pass the output of one command to another. When using EMS to retrieve objects, you need to be aware of the scope of your search and of how EMS handles name resolution.
By now you should know that Windows PowerShell, through Exchange Management Shell (EMS), can help you manage your Exchange Server environment. In "Exchange Management with EMS: Fundamental Concepts," I explained how to get PowerShell and EMS, and I outlined the basic pattern that EMS operations usually take: Get some objects, filter them to pick the exact set you want, then do something to them. In the remaining articles of this series, I’ll show you how to get useful things done with EMS, both by using interactive commands and by writing scripts. The articles listed in the Learning Path on the right side of the page can help you delve into the syntax and construction of PowerShell commands.
Remember that every EMS command consists of a verb, which tells EMS what you want to do, and a direct object, which tells it what you want the verb to apply to. To help avoid confusion with Exchange objects, I’ll use the term base to refer to the cmdlet object. For example, in the Get-Mailbox cmdlet, Get is the verb and Mailbox is the base.
What You Can Get
What objects can you retrieve and process with EMS? That’s a bit of a trick question because EMS includes cmdlets for retrieving all the object types and properties that Exchange supports. In Exchange 2007 SP1, that list includes everything from mailboxes to Exchange ActiveSync settings to public folder hierarchies. (EMS doesn't directly support retrieving the content and properties of items stored in users’ mailboxes, though; for that you’ll need to use Exchange Web Services.)
The Get verb is what you’ll use to retrieve objects that you want to manipulate. You should remember that when you get an object, you also get its properties. This detail is important because when you get a set of objects, you’ll often then immediately change one or more properties with the corresponding Set cmdlet. For example, say you want to set all your Mailbox servers to disallow connections from MAPI clients that don’t have encryption enabled. In this case, you don’t care what properties already exist; you want to set one particular property, which you could do like this:
Get-MailboxServer |Table 1 shows the most useful object types that you can work with, along with the related EMS commands. This list isn’t intended to be comprehensive; instead, it’s just a way to give you a quick overview of the range of things you can do with EMS. Of course, you can use these cmdlet bases with a variety of verbs, including Get and Set. In some cases, you can use Enable, Disable, Create, or Remove. However, in this article I want to focus on using Get to help you become accustomed to getting objects and their properties.
Getting Exchange objects is simplicity itself. If you want to get all the mailboxes in your organization, Get-Mailbox does the trick. If you want a list of mailbox databases, use Get-MailboxDatabase. And so on. Remember that the items returned by these commands are objects, not just text strings. When you retrieve a mailbox, for example, the returned object includes a variety of useful properties, such as the display name and the server where the mailbox is homed. If you want to see what properties come back by default with a particular object, pass the output to the Format-List cmdlet.
Speaking of Passing . . .
One aspect of PowerShell that I haven’t discussed yet is its ability to pipeline commands. Pipelining gets its name from the vertical pipe character, which signals that you want to pass the output of one command to another. In a text-based world, such as DOS or the Windows command shell, you’re probably used to the idea of typing things such as
dir /w | moreto pipe the output of a command to another text-processing utility. You do exactly the same thing in EMS (using the same character, even) but the results can be very different. Why? Because you’re not piping a stream of text; you’re redirecting a stream of objects and their associated properties. The difference is subtle, but important. If you open a Windows command shell and type
dir *.eml | delyou’ll get an error message. If you type the corresponding PowerShell command
dir *.eml | remove-itemPowerShell removes all files with a .eml extension in the current directory. The Windows example produces a stream of text listing the files, which the Del command can't interpret. The EMS example produces objects that represent the files themselves. Because these objects act like proxies to the underlying items, they can be moved, removed, or modified. As a thought experiment, consider what would happen if you typed
Get-Service | Stop-Servicein a PowerShell window—it would stop every Windows service on the machine!
There are commands you can use to turn a stream of objects into a textual or graphic representation. For example, the Format-List and Format-Table cmdlets take a stream of objects and display them (along with the properties you select) as a list or table, respectively. Other cmdlets let you turn objects into comma-separated value (CSV), HTML, or XML files. For example, a quick way to get a CSV file containing a list of mailboxes is to use
Get-Mailbox | Export-CSV c:\temp\mailbox.csvPipelining is a key part of the PowerShell process. You’ll use the pipeline operator to pass objects you retrieve to a filter or to other cmdlets that will take action on the objects.
EMS doesn’t distinguish between commands that return one object and those that return hundreds or even thousands. If you issue the Get-MailboxServer command in a single-server test environment, you’ll quickly get back an object representing the lone Mailbox server. The same command run in a large global Exchange deployment returns many more results—and it might take a while. For that reason, we need to talk about how to set the scope of commands to control what results come back.
By default, when you perform any kind of EMS query that retrieves data from Active Directory (AD), the results returned are limited to the domain to which the machine you’re using belongs. If you have more than one domain in your forest, this can lead to odd or unexpected results for your queries. Some cmdlets, such as Get-DistributionGroupMembers, let you specify a domain controller to search by using the -DomainController switch, which takes as argument the name of a Global Catalog (GC) in a specific domain. A more permanent fix is to tell EMS to scope queries to the entire forest by setting the AdminSessionADSettings.ViewEntireForest variable to $true, as described in "Setting Up Exchange Management Shell."
When using EMS to retrieve objects, you need to be aware of how it handles name resolution. There are several different ways you might want to retrieve objects:
- If you want a single object, specify its name, either as an implied parameter or with the -identity switch. For example,
Get-Mailbox -identity [email protected]matches only those mailboxes with the specified SMTP address. Different commands accept different values for object names. For example, the Get-MailboxDatabase cmdlet lets you specify the server name, the database name, the distinguished name (DN) of the database, or a combination of more than one identifying parameter. DNs are long and complicated, so you probably won’t want to use them to identify objects such as databases for EMS. Instead, you should have a solid naming convention in use within the organization so that objects can be referred to with an easily understood and logical scheme.
- If you want all the objects, you don’t need to specify a name criterion. For example, if you just want all the Mailbox server objects in your organization (subject to scoping restrictions as noted above),
Get-MailboxServerdoes the trick.
- If you want a subset of objects, use a wildcard expression that specifies the objects you’re interested in. For example,
Get-MailboxServer RED*finds all Mailbox servers whose names start with RED. (Note, however, that the search isn’t case sensitive.)
- If you want to use AD’s Ambiguous Name Resolution (ANR), use the -anr switch. AD has the ability to perform partial-match searching against several attributes, including the first name, last name, the mailbox nickname, the SAM account name, and the email account name. For example,
Get-Mailbox -anr "smit"returns entries for John Smith, Jan Van Smits, contoso\rsmith, and [email protected] ANR is supported by some EMS cmdlets, but not all of them; you can use Get-Help with any cmdlet to see if it includes the -anr switch.
By far the easiest type of name resolution is the default: just get all the objects, then filter them as necessary. This is a simple way to create queries, particularly when you have a small number of objects to retrieve. However, this requires you to retrieve every object and pass it to the client. That’s a poor practice in large environments; instead, you should plan on using server-side filtering, which I’ll cover in a future article.
Getting Specific Attributes
When you retrieve an object, it automatically has all of the attributes available for that object type. However, you can specify specific attributes when you filter and search—something I’ll cover in a future article. You can also tell Format-List and Format-Table to list specific attributes. For example,
Get-Mailbox | Format-Table Name,DisplayName,EmailAddressesgives you a neatly formatted table listing the names, display names, and email addresses for all your mailboxes. Of course, you could then pipe the output of Format-Table to the Export-CSV cmdlet, and so on.
Don't Be Afraid to Play
The best way for you to learn how to work with EMS is to experiment. Luckily, everything I've discussed here is completely nondestructive. There’s no way you can hurt your Exchange servers or objects by using the Get verb, so go ahead and play around. In the next part of this series, we’ll learn how to set properties and create objects, as well as a few tricks for making sure that you can do so without causing damage