Exchange 2007 Scripting Corner: fix-alias


One of the things that I have liked the most about the move to Exchange 2007 is the introduction of PowerShell into the management of Exchange. PowerShell is a very powerful tool that the Exchange administrator now has in their arsenal. Many regular, advanced and or mundane tasks can now be automated with PowerShell scripts or commands.

To help demonstrate what we can do with PowerShell, and get you the administrator interested in writing your own scripts, I hope to start posting a series of scripts (as I am able to write them) to the EHLO blog. The intent is that these scripts will solve a problem that you the Exchange administrators are having and will work as a way to teach PowerShell scripting thru example.

The first script I have for you is to solve a problem I have seen coming in on the phones here at Microsoft a few times. As our customers are migrating from Exchange 2003 to Exchange 2007 they are finding that some of the aliases of their contacts, users, or distributions groups contain invalid characters. If there are only a few it is simple to modify them by hand, but in many cases there are 10s if not hundreds that are incorrect.

With PowerShell and .net we can write a script that will correct this issue easily for us. Now most of the documentation of the script is in the comments sections of the script itself; but, I am going to go over the script flow and a few key things that I use in my script writing.

Script Flow:

At the bottom of the script your will find the Main body. This is actually where we begin processing.

  1. First we determine if the user has requested the help documentation using the –help input parameter.
  2. Next we check if the –type switch was passed otherwise we ask the user to choose and set the type of objects to look for.
  3. We construct the get command we will run into a variable (this is the best way to build “complex” commands to execute via multiple script inputs)
  4. We call and move into the FixObject Function
  5. The FixObject function is where the work is actually done
  • Execute the command we built and place the output in an array
  • Look thru each member of the array for our bad character
  • Replace the bad character when found (here we actually use a .net method from within PowerShell)
  • Build and execute the modification command

The true power of PowerShell I have found is in the ability to create functions. With a function you can encapsulate a given set of actions and then call those actions over and over again as needed in the rest of your script. In this script we use two functions ShowHelp; a function that appears in almost all of my scripts to provide the user with a “help” file on the script, and FixObject; the function that actually does all of the work in the script.

The other amazing power of PowerShell that we use in this script is the string.replace method. We are able to call that method directly from within PowerShell. Just to get an idea of the potential of PowerShell and .Net try this at a PowerShell prompt. Create a string Variable and set the value of the variable. (e.g. [string]$new = “Test” ). After setting our variable we will type the name of the variable followed by a period at the prompt. (e.g. $new.) Now simply press the tab key. What you will see is that you are now rotating thru the string methods available in .Net.

I would like to explicitly solicit feedback on this post. Did you find this ramble and the associated script helpful in showing some of the things that PowerShell can do and how to do them? Did this encourage you to write a script of your own? Also I would like to solicit Ideas from you on what you would like to see PowerShell do; and I will look into turning your Idea into my next posted script.

You can get the fix-alias script here: Fix-alias.PS1 script

Matthew Byrd

Comments (17)
  1. vivek says:

    "2007 Scripting corner" — that is a really cool idea. Looking forward to more entries.

    The script is really cool, the idea of prompting users through fixing things, is great, and the implementation is neat—I really like the use of invoke-expression here. Nice work.

    Minor optimizataion: use here strings @’ ‘@ to encapsulate large chunks of multi-line text and reduce the number of write-host lines you have to write.

    Minor nit: I typicall avoid using aliases in public scripts (e.g. iex) as most folks won’t know what the alias is.

  2. Thank you for the cool script Matthew. Is there a list of invalid characters? Christian

  3. Garry Trinder says:

    In your mail you only sent /files/12/… as link…

    :)

    Klaus

  4. cooks says:

    I do find this to be rambling for someone who has not yet written a powershell script which would be me. At this point I’m more interested in how to use powershell to automate tasks rather than run interactively. You can get good information from powershell but how can this be used in web sites or with a monitoring product? Can I receive output from running a powershell script without using vb or C with a pipeline?

    Hope these questions are not outside the scope of what you are trying to communicate.

  5. Matbyrd says:

    Hi Vivek,

    Thank you for the response and the suggested optimizations … I will be using both of those going forward.

    Hi Cooks,

    You can use powershell to return data directly too you in all sorts of forms.  XML, CSV, HTML etc … you can even further manipulate the data directly in powershell.  Powershell has access to all of the .net classes so you can do just about anything that .net can do right in powershell.

    What are some tasks that you would like to see automated … and or information that you would like reported.

    Thanks again for the feed back … if anyone has anything furher please post away … :)

    My Next Scripting corner is in the works and I am looking to do some one liners that help with basic automation stuff.

    -Matt

  6. Cooks says:

    An example of what I would like to accomplish is have a monitoring program run a script and send an alert based on the output of the script. Particularly run get-storagegroupcopystatus and if either the CopyQueueLength or ReplayQueueLength are too high then send a notification message. There are multiple other command I can see using in this same way.

  7. Petri says:

    I’m a bit surprised how much you are driving the powershell and scripting together with it. Are there real so many tasks on Exchange server which requires you to run script prefer GUI ? I’m asking this because I have no idea…..yet :)

    e.g. fixing the alias after migration, sounds that migration process is not finalized or something else went wrong. But in my mind task like this is once in lifetime and these are totally to AD related.

    Or the alert systems…. don’t we have monitorin tools for monitoring our environment, instead of script based.

    Or creating new storage group, okay, that might be nice, but again once in a lifetime.

    So please don’t forget the GUI…

  8. Matbyrd says:

    Hi Petri,

    The Exchange team has not fogotten the GUI.  They are planning some major enhancements to it comming in SP1 and there might be even more in SP2.

    What powershell does is give you an incrediably powerfull tool for performing tedious tasks quickly.  This script was just one example where in 20 minutes I was able to write a script that would fix any number of affected object in my environment ( I know personally I have worked with customers that had over 150 affected objects).

    But this script is an example of a more complex script that can be written to I rapidly solve a problem you are having (I will admit this is a one off resolution).

    I will try to provide you with some quicker one liners that can be used over and over depending on your needs.

    -Matt

  9. Norah says:

    May I know what are the characters found to be invalid on the alias in E2K7 so that I can ask my customers to check before migrating E2K3 mail objects. thanks!

  10. Matbyrd says:

    Hi Norah,

    Here is the output of Powershell when we have a bad object.  This lists the valid characters for an object.

    WARNING: Object nce12.org/DragonsRest/dragon49 has been corrupted and it is in an inconsistent state. The following

    validation errors have been encountered:

    WARNING: "dragon 49" is not valid for Alias. Valid values are: Strings formed with characters from a to z (uppercase or

    lowercase), digits from 0 to 9, !, #, $, %, &, ‘, *, +, -, /, =, ?, ^, _, `, {, |, } or ~. One or more periods may be

    embedded in an alias, but each one of them should be preceded and followed by at least one of the other characters.

    Unicode characters from U+00A1 to U+00FF are also valid in an alias, but they will be mapped to a best-fit US-ASCII

    string in the email address which is generated from such an alias.

  11. ryan says:

    When I run this script it bombs out (though probably through no fault of Mat’s) after, I’d expect, about 1000 objects have been searched.  I get loads of warning messages on screen and then the thing pauses for over five minutes. Doh.

  12. Matbyrd says:

    Hi Ryan,

    I would recommend restricting the script to a single OU at a time.  The script is already setup to take additional inputs for additional filtering.  When you run the script simply add the following to your existing command.

    Fix-alias -add "-organizationalunit ‘My Ou’"  that should restrict the script to searching just that OU.

    You could even go further an modify the get command to do a get-excahngeserver first and only process the mailboxes that are on a given server at a time.

    That would look something like get-excahngeserver | foreach { get-mailbox -server} | …..

  13. Raymond Diack says:

    Hi Matthew

    Great script – thanks!  One minor bug – when running it against contacts that have a third parameter in the alias then the set command doesn’t work. – e.g. "John Smith (foo)".  It interprets the "foo" bit as another parameter and bombs.  Fixed it by adding single quotes to the -alias bit around "$new" on line 84:-

    Old:

    $setcommand = "set-" + $type + " ‘" + $value.identity + "’ -alias $new"

    New:

    $setcommand = "set-" + $type + " ‘" + $value.identity + "’ -alias ‘$new’"

    Hope that doesn’t break anything else, but i don’t think so.

    Thanks

    Ray

  14. Chris says:

    Is there a way to pass multiple characters into the script  I have a great deal of contacts with both @ and ; in the alias and am looking for a way to change both.  When I run the script against either it is unable to write the new alias because it still contains an invalid character.

  15. jbrines says:

    I like the idea of a scripting cornor.

    I want to try an use the scipts more to get more information about our system.

    We have 19 mailbox servers over the world in one system, we set all our users to have the same mailbox quotas but have instructed our site admins to notify us of any change on the user mailbox quotas. IS there a way in a script to show me what a users quota is and then run that against multiple mailbox servers?

    John.

  16. Matt says:

    Hi Jbrines,

    Quotas are actually stored as AD attributes, so you can just use get-mailbox to find out what a users current quota value is.  If they have a value that differs from the default store limit the value of UseDatabaseQuotaDefaults will be set to False.  So a simple one line command like:

    get-mailbox -Filter "UseDatabaseQuotaDefaults -eq `$false" -ResultSize Unlimited

    Will get us all of the users whose quota is not the default mailbox store value.  Then simply adding a | export-csv will export all of the information about the users to a CSV file where you can import it into Excel and do anything you want with it data manipulation wise.

    get-mailbox -Filter "UseDatabaseQuotaDefaults -eq `$false" -ResultSize Unlimited | export-csv c:quota.csv

  17. Matt says:

    Chris,

    To get this to work should just be a minor change.  Change the following line

    $new = $new.replace($search,$replace)

    To be:

    $new = $new.replace($search,$replace)

    $new = $new.replace(“;”,”_”)

    Then run the script as you normally would to get it to do the replace for the @ sign.  At that point it should change the @ sign as normal and then should change the “;” to “_” … it will do all of that before it goes to run the set command.  Feel free to change the “_” to a character of your choice.

    As always please test on one user prior to running in bulk… your mileage may vary

    -Matt

Comments are closed.