Moving Mailboxes the easy way

#MSExchange

So I have moved quite a few mailboxes from Exchange 2003 to Exchange 2010.  I have shared some of my pain (http://flaphead.dns2go.com/?p=2917) and wanted to share what I actually do.

Those that know me, would know that I am not too bad with Powershell Winking smile and the obvious thing to do is to script these moves.  So probably on Friday, I will post the scripts, but this is how things work for me.

So before we start, the reason for the different scripts is #1 so they can be run by themselves, and #2 automation is a great thing, but I am a control freak and want to be able to control things just in case things go pear shaped!

It all starts with a list of email address. I put them in a csv file with a single heading of email

I then run my first script: pre-flightchecks.ps1

This script checks the AD site that I am running the script from, enumerated the CAS servers and runs Test-MRSHealth on each CAS server to make sure its happy. 

Next it checks to make sure all the databases in the AD site are mounted on the server that has an Activation Preference of 1.  A bit of qdos for this, is that the code can be found on page 491 of Microsoft Exchange 2010 Inside Out by Tony Redmond [Thanks Tony for the mention Open-mouthed smile]

Finally the script reads the CSV file and checks to make sure all the mailboxes have IsValid = True.  Due to the age of the system I am migrating at the moment, we are find a lot of mailboxes, groups and contacts that are “invalid” as far as Exchange 2007 & 2010 are concerned.  The most common issues are bad Alias Names (having commas in), database names that don’t exist anymore (don’t ask!), invalid UPNs and display names with trailing whitespace.  Oh the other thing it checks is to see if the mailboxes already have move requests associated with them!

So once complete we know that MRS is cool, the database are where they are supposed to be and the mailboxes are valid

Script #2 is Move-RequestFromCSV.ps1

As the name suggests it takes the CSV file I have with email addresses and then generates move requests.  It does a few other smart things, but the kinda cool thing is that is autogenerates a BatchName and all the moves are given the same batchname.

Now if you have not played with move requests before, the batchname is excellent and Devon put me on this a a long while back.  What is cool is that you can then reference all the move requests in a batch and treat them as one .. really cool

So the move requests are in flight, what next

Well Script #3 – Monitor-MoveRequest.ps1

I just love this script.  In an nutshell, this uses the BatchName from the previous script and just sits and monitors the progress.

Something Ari has been beating me up about for a while, is that where I am now we don’t have SCOM, so I have written a poor man monitoring website with static html pages that are updated by a handful of powershell scripts.  I must admit it is rather bloody cool.  Maybe one day I will get round to doc’ing it!

So the monitor script generates a html page every 20 seconds or so until the moves are complete.  All you have to do it open the html page and watch.  It is a bit like watching paint dry.  [On a side note what is interesting is how tollerate move requests are to bad slow network links.  I move 60 odd mailboxes over the weekend where it peaked at a massive 3MB per min!  Took over 8hrs to move a 1.9TB mailbox!]

Once complete it sends the html page in an email as the message body as well as the reports from the move requests.  These reports are golden, especially if you the move has failed for any reason.  If you want to see normally you want view a move request in the Exchange Management Console, or run somethng like (Get-MoveRequestStatistics <user email> -IncludeReport).report

An that’s it, only another 7000 odd to go now!

Oh I almost forgot!  So driving home last night I was thinking about how to distribute mailboxes across databases [Coding in  my head is scary].  Yeah I know this is old skool and that plenty of people have done this before.  Steve’s example is good [http://www.stevieg.org/2010/09/balancing-exchange-databases/] BUT I couldn’t resist, and Mitch has been on at me to do something, so I did.

I got my Wife involved too, and started with an explanation of pots filled with coins and that I wanted the same number of coins in each pot.  She came up with a idea (after I got the WTF are you taking about look) and so last night v0.1 of  Get-DatabaseDistribution.ps1 was born

So you think coding while ur driving is bad, well last night instead of counting sheep I was working on part 2.  So I explained this to my wife this morning, as the same pots filled with coins, but now I want to make sure all the pots has the same coin value in them. I think I burned her out of ideas last night and only got a WTF this morning.

BUT I think I have cracked it.  Been testing it today with both Distribute by Count and MB and it looks good.  What is even better is that is generates a CSV file, and I can use the combination of the 3 scripts above.

Looking to share the scripting love probably Friday

l8trs

Powershell Format-Table HELL!

#Powershell

This really is killing me, I am getting it more an more.

Basically if I create an array I want to send the output to the screen using Format-Table.

In the shell it works fine, but when I use a .ps1 I am constantly getting

out-lineoutput : The object of type "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" is not valid or not in the correct sequence. This is likely caused by a user-specified "format-table" command which is conflicting with the
default formatting.
+ CategoryInfo : InvalidData: (:) [out-lineoutput], InvalidOperationException
+ FullyQualifiedErrorId : ConsoleLineOutputOutOfSequencePacket,Microsoft.PowerShell.Commands.OutLineOutputCommand

What the hell is going on?! Why is the shell different to a .ps1

I don’t want a list, all I want is a table! .. Select-Object can’t make up its mind if it want to use a table or list and I done see anyway around it .. Event exporting to CSV and reimporting fails!