Thursday, March 27, 2008

Modify Exchange 2003 Users Primary SMTP addresses with Powershell

I have worked with address updates and Msmail/Exchange since the very first 4.0 beta and have been scripting/hacking since before with MSMail and dirsync issues. The latest and greatest scripting choice is powershell and I am embracing this and the community tools as eagerly as I can. PowerGadgets, Quest AD Powertools, PowerGui and a bunch of other open projects really have what it takes to push powershell to do whatever needs to be done. With Exchange 2007 really built on powershell, the jump from 2003 to 2007 is going to be a reach for some of the administrators. I am highly recommending that ALL exchange 2003 administrators dive into powershell, even if you don't know how to spell scripting. I just went through Ed Wilsons Microsoft course introducing powershell and can't rave about it enough. Ed's got the skills and knowledge that really helped our group drive out some good discussions and even better knowledge transfer.

Before going into the course I had setup some goals for myself. Knowing that we are going to be with Exchange 2003 for at least another year, and that planning for 2007 is critical, I thought I would learn powershell using Exchange 2003 and then catapult myself forward for our 2003-2007 migration. One critical item we do in our infrastructure of 12k users is modify Primary SMTP addresses more often then not. We can use tools, ADMODIFY, VBscript and now powershell. The big problem with modifing the users addresses is that there is no real way to change the address and ensure we don't inject a duplicate SMTP address. The RUS in 2003 tracks this and ensures that duplicate addresses are not created. Playing with scripts can really wreak hell on your AD and Dup addresses pretty much make email delivery to that user null. So after some testing and some playing I have written some scripts that will do this for me. I am using the Quest AD powershell tools, thanks guys, and have come up with the following 2 scripts

Script 1
Concept - Test change a Primary SMTP address
Reads a group
Loops through the group
Gets each users Primary Mail address and the Proxy addresses
Defines a new SMTP address
Does an LDAP Query to ensure it doesn’t exist in the domain
Prints out if it would have changed it or not

Script 2
Concept - ChangePrimarySMTP addresses on existing users
Reads a group
Loops through the group
Gets each users Primary Mail address and the Proxy addresses
Defines a new SMTP address
Does an LDAP Query to ensure it doesn’t exist in the domain
If the address exists it just bails out to the next user
If the addresses doesn’t exist it starts a loop
Looks at each smtp address the user has defined
If finds the Primary smtp (defined by a capital SMTP: ) Change it to a lowercase smtp: (makes it not primary anymore)
Ignore all others
Add in the new defined SMTP address to the Proxy addresses and make it Primary by using SMTP:
Update the windows mail address (on the general tab) so it matches the users Primary SMTP just defined
Loop until done

I have more code to write but full meat and potatos are as follows

First script - TESTS only

$g=get-qadgroup -display "Test Mail List"
for ($members=0; $members -le $g.member.count-1 ;$members++)
{
$b=$g.member[$members]
$c=[ADSI]"LDAP://$b"
$primarySMTP=$c.mail
$email=$c.proxyAddresses
$first=[STRING]$c.givenname
$last=[STRING]$c.sn
$newaddress=[STRING]$first+"."+[STRING]$last+"@domain.com"
$already=get-qaduser -searchroot "adname.com/" -LdapFilter "(proxyaddresses=smtp:$newaddress)"
if ($already.dn -eq $null)
{
"$PrimarySMTP Gets a new Primary SMTP address of $newaddress"
} Else
{
$already.name + " already has this Address $primarySMTP"
}
#$newaddress + $c.mail
}

Second Script adds a new SMTP address without clobbering the old one

## Read from a group the users you want to change#
$g=get-qadgroup -display "Test Mail List"
#
for ($members=0; $members -le $g.member.count-1 ;$members++){ $b=$g.member[$members] $c=[ADSI]"ldap://$b/" $primarySMTP=$c.mail $email=$c.proxyAddresses $first=[STRING]$c.givenname $last=[STRING]$c.sn $newaddress=[STRING]$first+"."+[STRING]$last+"@domain.com" $already=get-qaduser -searchroot "ADDomain.com/" -LdapFilter "(proxyaddresses=smtp:$newaddress)"
##Check for a Dup SMTP if not, write a new one, if so Bail #
if ($already.dn -eq $null){"$PrimarySMTP Gets a new Primary SMTP address of $newaddress"
#Get All the SMTP Addresses and change the old Primary to a secondary
for ($address=0; $address -le $email.count-1 ;$address++){ $email[$address] $text=$email[$address] $up=$text.substring(0,5) #$up if ($up -ceq "SMTP:") { $low=$up.tolower() $oldprimary=$low+$primarySMTP "Primary Address $text has been Changed to $oldprimary" $email[$address] = $oldprimary }}$c.proxyaddresses+="SMTP:"+$newaddress$c.mail=$newaddress$c.setinfo()
} Else
{$already.name + " already has this Address $primarySMTP"
}
#$newaddress + $c.mail}"done"

Here are a couple links
http://www.murmans.com/MostlyMail/PrimarySMTPChange.txt
http://www.murmans.com/MostlyMail/testSMTPRename.txt

more to come on my next blog!

Tuesday, March 18, 2008

Ed Wilsons Powershell Tour To Regina, Sk

I want to thank Ed Wilson for coming into Regina for our initial powershell course. The technical content is great and the information that can be pulled out with Powershell is simply awesome. Ed has a technical savvy that would put most codes out to pasture. He really understands the underlying fundementals that make a good class very good.

So what have I got from this class? My inital goals were to take some Old VB scripts that I had written years ago for my Exchange 2003 project. I am working on translating and enhancing these reports. Certainly powershell makes this a Snap. Here is the first and most basic script. I want to get the WhiteSpace information out of a remote Exchange cluster 2003 server where powershell is not installed. This is my first cut at it and I will look at adding totals and more information soon. Stay tuned for a few more scripts....

# Setup the Eventlog for the application log on a Remote server
$log = new-object system.diagnostics.eventlog("application","ServerName")

# Prepare a table in HTML to house the information (Right from MS!)
$a = ""

#Prepare to generate a CDO message to email the report
$mail=new-object -comobject cdo.message
$mail.From = "report@mydomain.com"
$mail.To = "Someuser@mydomain.com"
$mail.Subject = "White Space report for " + $(get-date)

# Set the HTML body of the Email the actual report - This is the meat and potatos of it
$mail.htmlbody=$log.get_entries() where-object { $_.timewritten -ge (get-date).adddays(-1) -and $_.eventID -eq 1221}
select-object -Property EventID, MachineName, Message, TimeGenerated convertto-html -head $a -body "

PowerShell Whitespace Report for Exchange Cluster

"



# Complete the email and send it out

$mail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
$mail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtpRelayServer@mydomain.com"
$mail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
$mail.Configuration.Fields.Update()
$mail.send()