EDIT: This post has been updated on 10/15/2007 to incorporate feedback we received since original posting.

So my last post demonstrated a script that used a .net method and some functions within the script to take care of a problem that was a little hard to solve manually. The feedback I received was generally positive but some folks indicated "why is PowerShell useful to me"... "why should I lean how to script these are all one off situations"? To an extent I will agree with you.

If you are a smaller shop say 1 to 2 servers then there might not be as much value in leaning to write complex Powershell scripts. Most of what you are going to do on the server is going to be for one off situations (create storage groups, create databases, move mailboxes, etc). So for this installment of my scripting corner I have tried to come up with command that meet two criteria. 1) The command can be written on "one line" within PowerShell and 2) The command is something that I could generally see being used on more than one occasion by the same company.

The scenario that I came up with is one we see here on occasion; where an end user will send out an email to an unintentionally large group of users or will send a message out with information that went to a distribution group or set of users that it should not have. In both of these cases there is not a good end user powered way to get these messages back out of the Database once they have been delivered. For Exchange 2000 and 2003 we had the Exmerge tool that could extract these out for us. In Exchange 2007 we have the Export-Mailbox cmdlet.

So here we have the command that you can run that will go thru the organization and move all of these unexpected messages to a target mailbox.

Get-mailboxserver | foreach {Get-mailbox –server $_.identity -resultsize unlimited | export-mailbox –subjectkeywords "Bad Message" -targetmailbox <newmailbox> -targetfolder Deleteme –deletecontent –confirm:$false}

So let's break this one liner down for the key pieces that it uses. The biggest thing that we use here is pipelining "|". The pipeline allows us to take the output of one cmdlet and send it directly to another cmdlet. The cmdlet further down the pipeline will need to understand the output of the proceeding cmdlet, but as long as you use a little common sense this is usually not an issue.

We are also using foreach (the alias of foreach-object) to setup an execution loop. When pipelining in from another cmdlet to foreach loop the foreach will execute against each of the outputs of the proceeding cmdlet. In other words if our get-mailboxserver returns five objects, we will execute the foreach loop five times.

This pipelining the output of a cmdlet into foreach (foreach-object) is one of the most common things that I end up doing when writing any script.

Within the loop itself we are doing another pipeline. In this case we are taking the output from the get-mailboxserver cmdlet and using the identity property ($_.X Means use the X property from the object coming down the pipe) to search for all mailboxes that are located on that server. Once we have gathered up that set of users we pipeline it into the export-mailbox cmdlet and use that cmdlet to do the work.

The export-mailbox cmdlet we have setup will simply search all of the mailboxes we give it off the pipeline for any messages that have the specified keywords in the subject and then move them to our target mailbox into a folder called "Deleteme".

Now the big question that some people might be asking is why I didn't just use a much simpler Powershell command to do this process.

Get-mailbox -resultsize unlimited | export-mailbox –subjectkeywords "Bad Message" -targetmailbox <newmailbox> -targetfolder Deleteme –deletecontent –confirm:$false

After all doesn't that accomplish the same thing? The answer is yes and no. If you have a small environment with let's say less than 5000 users or so then the shorter command above is perfect for you. If you have an environment that is larger than that then you will want to use the foreach command to streamline the process.

The reason for this is that the export-mailbox cmdlet is a multi threaded cmdlet so it is going to force the aggregation of all of the mailbox objects before it begins operating on them. (To identity if a cmdlet is a multi threaded cmdlet look for the –maxthreads switch.) Since that is a limitation of the current cmdlets we are working with in a large environment operating on the users on a per server basis will get things started faster (since we won't have to wait on AD to return all 50k objects to get started) and will be less resource intensive.

Hopefully I have accomplished my goal of showing everyone a little bit more about Powershell and sharing a script that will be of use more than once for people. Again I would like to solicit feedback from you the reader on how you liked this article and if there is anything you would like to see turned into a script. Otherwise I will just have to make something up for my next post and who knows what I will think of.

- Matthew Byrd

Share this post :