Posts
49
Comments
83
Trackbacks
0
September 2006 Entries
Sorting top users and then moving them (2003/2007)

Brian asked in the comments: "... I am looking for a monad scipt/command that will allow me to sort user on e2k3 by size then move either the top or bottom X number of users..."

Try this on Exchange 2007, for 2003, you can use get-wmiobject cmdlet to read Exchange 2003 information using WMI. This is how you would get the top X users per server (you can optionally do this per database by passing in -database to get-mailboxstatistics):

get-mailboxstatistics -server Myserver | sort TotalItemSize -desc | select -first 10

Then you can move this list directly using move-mailbox:

get-mailboxstatistics -server Myserver | sort TotalItemSize -desc | select -first 10 | move-mailbox -target Server2\DataBase2

For 2003, its a bit more complicated as we don't have cmdlets for 2003, but fortunately you can use the excellent WMI compatability in PowerShell to read Exchange information. For example:

 get-wmiobject -class Exchange_Mailbox -Namespace ROOT\MicrosoftExchangev2 -ComputerName MyServer | sort Size

This will return a list of mailboxes, which is then sorted, then you can apply the same tricks as before. The one big difference is that since we're dealing with WMI objects (as compared to get-mailboxstatistics objects as in Exchange 2007), you'll have to tweak the pipeline to make things work for moves:

get-wmiobject -class Exchange_Mailbox -Namespace ROOT\MicrosoftExchangev2 -ComputerName MyServer | sort Size -desc | select -first 10 | foreach { move-mailbox $_.LegacyDN -targetdatabase server2\database2 }

Now, a caveat.... I believe this should work but having upgraded all my servers to 2007, I can't quite test it :) Also, please refer to this post by Glen for more information. I believe I've given enough data to point you all in the right direction, so give it a shot and play around with it. Remember, you can always use -whatif and -validate in move-mailbox, which means you can run the commands without any fear :)

posted @ Tuesday, September 19, 2006 5:09 AM | Feedback (1)
Guess who’s back… back again!

As you can tell, I'm back from my month long vacation. It was great! I visited family in India and made my way to several awesome places and also visited Katy in Nepal, pictures to be posted later when I sort through all 1,000 of them!

Anyway, thought I'd kick off blogging again with some fun tricks. If you read the MS Exchange Team blog, you would have spotted the article on The Secret Decoder Ring. Long story short, the default admin group and routing group in Exchange 2007 are named quite oddly:

Exchange Administrative Group (FYDIBOHF23SPDLT)
Exchange Routing Group (DWBGZMFD01QNBJR)

I actually didn't know what they meant either... only a few people on the team knew. During a presentation by a fellow PM on the team on the subject, I decided to solve the puzzle using PowerShell. Here is how I got started.

#1. Assume the letters are the results of a cipher

In all ciphers, there is a generating function, so the goal is to guess the generating function. If you can guess the generating function, you can work backwards and construct the original message.

#2. Use PowerShell to examine each letter

We want to look at each letter in a sequence. There are several ways of doing this:

Boring standard way:

$str = "FYDIBOHF23SPDLT" 
for($i =0; $i -lt $str.Length; $i++) { $str[$i] }

Cool powershell way. First examine what is available for you to use using get-member or gm:

"FYDIBOHF23SPDLT" | gm

You'll see that Strings have an interesting method:

GetEnumerator Method System.CharEnumerator GetEnumerator()

You see that it returns a CharEnumerator. What does this do?  Best way to find out is to try it out:

PS> "Test".GetEnumerator()
T
e
s
t

As you can see, each character in the string is returned immediately as a seperate entity. Useful.

#3. Now that we know how to get to each letter in the coded message, its time to guess the generating function. We know that each letter represents an actual value, so it should be straightforward to automate "guessing" the function. From past experience I knew that text ciphers are generally based on a either a rotation scheme (each letter in a code represents another letter). So the best place to start is to write a script that takes the string and then strong arms the rotation (i.e. runs the text through different rotations):

"FYDIBOHF23SPDLT".getenumerator() | % { [char]([int]$_- 20 } 

What is the above doing? Let me explain what's going on. The result of the call to GetEnumerator() returns characters, which are then passed to a foreach that basically rotates that letter by a given number (in this example it rotates each letter by 20). But that actually returns another list of characters, which is a little annoying. That's not the main problem, its still not automatable, but at least if we had pure human labor and this was a real code to crack, we could throw humans at the problem by letting them guess arbitrary numbers. The real world code crackers, however, rely on automation.

Another explanation of what [Char] [int] does. Each letter returned is a "char" which in technical lingo is a special type representing a readable or non-readable character (like "L"). Well we need to be able to operate on this as a number for our code cracking, so we need to cast it to a number or integer. This is done by applying [int] to the value we want to covert. In PowerShell all literals are either string or nums at the end of the day, so you have to be careful of this trick. For example:

[int]'f'

fails but:

[int][char]'f'

works. Can you figure out why? Anyway, back to the exercise, in our case remember that GetEnumerator() returns a CharEnumerator, which coincidentally is a char, so we just need to cast the current letter coming through the pipeline to a [int] and then operate on it, in our case rotating negatively (subtracting) the current char by the given rotation amount. For example: Rot = 1, letter = B, code = A. This is because if you walk back from B by one letter you get A.

#4. Automate the function to walk through a huge list of rotatations. Step #3 gave us a way to apply a rotation

filter guesser
{
  $rot = $_ 
  "FYDIBOHF23SPDLT".getenumerator() | % { [char]([int]$_- $rot }  | &{
    process 
    {
      $local:s += $_ 
    }
    end
    {
      $s 
    } 
  }
}

This looks complicated but really what its doing is defining a function that takes numbers and then applies those numbers as rotations to the code. So for example, this works:

PS> 1..5 | guesser
EXCHANGE12ROCKS
DWBG@MFD01QNBJR
CVAF?LEC/0PMAIQ
BU@E>KDB./OL@HP
AT?D=JCA-.NK?GO

And whoala, there's our secret right there. Looks like the code was using 1 as a rotation :)

To impress your friends (or scare away the ladies), knowing that the rotation is 1, in the future you could just do this:

"FYDIBOHF23SPDLT".getenumerator() | % { [char]([int]$_- 1 } 

But wait, what about the other message DWBGZMFD01QNBJR? You'll find that 1..200 doesn't yield anything useful. But you should be able to figure that out without changing any of the functions above. Its a nice PowerShell trick that I will leave as an exercise.

posted @ Saturday, September 16, 2006 5:09 PM | Feedback (2)
Community Run Scripting Contest

Thanks to Josh for organizing this. In addition to the offical Microsoft One-Liner contest for Exchange 2007, Josh has started his own scripting contest for PowerShell and Exchange. The best part about it is, that the winner gets a signed copy of the upcoming PowerShell book from Bruce Payette, one of the leading designers of PowerShell!

Wow, nice job Jeffrey and Josh. So go forth and submit some scripts to both the official contest and Josh's. To sweeten the deal, if you end up winning either contest, I'll put your name, company, winning entry etc. on the official team blog (2 million readers per month), my blog, the Exchange Wiki and the PowerShell team blog... the publicity and fame alone is worth at least a few thousand dollars of advertising money :) 

posted @ Saturday, September 16, 2006 2:09 PM | Feedback (2)
News
A little slow these days as I'm busy working on exchangelabs.com. I will try and post tidbits when I get some time. Enjoy the older posts till then!