Exporting Exchange 2003 Mailbox Information

One of my peer departments is working on spamming the corporation. This internal spam, aka Corporate Newsletter, is to go out to everyone with a mailbox in the corporation. Unfortunately, a number of these people have abused their rights and their mailboxes are limited to receiving e-mail from only their managers.

In Exchange 5.5, you could create a simple CSV file and run the Admin tool to gather this information. Unfortunately, in Exchange 2003, mailbox settings are now integrated into Active Directory (AD). AD maintains all the mailbox information and settings, whereas the Exchange Admin tool is simply for server management (mail routing and global limits, etc.).

Then, how do you gather this information? I being the lazy, programmer-at-heart, that I am, wrote a VBScript to export the information. This worked great as I could set variables in the script to export the information I needed. This only worked for about a month, as I wanted pass this tool along to the internal employee for use (no way I was going to run this each time someone new was hired!!). That's why I put an HTA front-end on it!

To Use The Script

  1. Download attached ZIP and decompress to your hard drive.
  2. Modify the code to match your environment. Using Notepad without word-wrap turned on, will allow you to use CTRL+G to Go to specific line numbers.
    • Line 321 - modify LDAP query for your environment. We have seperate OU's for each affiliate office. The dropdown includes an option for each OU.

      <select onChange="" name=ClassesPulldown>
        <option value="'LDAP://dc=corp,dc=ent'" >All OUs
        <option value="'LDAP://ou=users,dc=corp,dc=ent'" >Users OU Only  
      </select>

    • Line 99 - Modify the Select Case statement to include each of the OU's.

      Select Case ClassesPulldown.Value                      
         Case "LDAP://ou=users,dc=corp,dc=ent"
              strExcelPath="Mailbox_Export_"&today&"_Users.xls"
         Case else
              strExcelPath="Mailbox_Export_"&today&"_All.xls"
      End Select

  3. Make sure you have Excel installed on the local computer.
  4. Double-click HTA file and run. My export of the entire environment takes about 5-10 minutes for 3,500 mailboxes.

NOTE: We have set Custom Attribute 1 (aka ExtensionAttribute1) to a value (1, 2 or 3) for group or resource mailboxes. For example, the Postmaster mailbox has a value of 1,Conference rooms have a value of 2. Line 121 of the code is designed to filter on these values. Remove the line completely to get all mailboxes, or modify it for your environment.

Update August 16, 2007: I've modified the code to query the local AD for it's structure, so the above modifications are not necessary. After I made the changes, it started timing out when running the query, which shouldn't be related to the script changes. I suspect slowness in my AD.

AttachmentSize
User Export Report.zip3.72 KB
User Export Report 2.zip4.7 KB

Assign Secondary Account Permissions to Distribution Lists in Exchange 2003

The company I am working for has a slightly different security model than I've seen before. It is probably because the largest Exchange server I've supported previously only had 3,000 mailboxes. This one supports 10x that number, with plans to grow to over 100,000 mailboxes by this time next year.

With that, they use a seperate "security" domain for logon and authentication than the "resource" domain where their mailboxes reside. This means that the account you logon to your computer, may not be the same account you read your email from. That account will need to be granted secondary permissions to that mailbox, aka "Associated Exernal Account".

Along that same strain, you can no longer simply assign permissions to a user via the Managed By tab. Their mailbox is assigned permissions, but you need to grant their security account permissions also if the group owner wants to add/remove members.

That's why I developed this script. This script will assign Manager permissions to a distribution list. It assigns the selected name rights on the Managed By tab, then assigns the "Send As" and "Write Members" permissions on the Security tab to the selected user's Associated External Account.

There are a few limitations/warnings:

  1. It doesn't work with DLs that contain commas in their display name. It will present this groups in a popup box when you query the OUs. This may be resolved as of my latest release.
  2. If you attempt to query all DLs in an OU, it may return only a portion of them. Use the Contains functionality to filter the results. It works similar to a SQL LIKE command, in that it will return DLs that contain the phrase anywhere in it. (no wild cards) Found it was having issues with punctuation, like back slashes in names.
  3. It does not remove the old owner's permissions from the security tab. Heck, this could be useful when assigning additional owners to a single DL.
  4. I have not tested the script yet against a new owner without an associated external account. It will attempt to assign to the NT_DOMAIN\SELF account of the user.

I've cleaned up the code, so it no longer asks for a specific OU. It will query your entire domain for the specified DL. To run, double-click on the downloaded HTA and have fun!

Note: I have recently (3/26) updated this script to filter on the entries, instead of search each one. This makes the overall process rather quick.

Update (6/6/2008): I have added code to allow you to remove people from the security settings on a DL also. Currently working on an issue that generates an error when dealing with an apostrophe in the distinguished name (for example ldap://cn=Eric's Big List,ou=groups,ou=ericwoodford,ou=local). VBScript is taking it as the end of string and breaking..

AttachmentSize
SetNewDLManager.hta18.81 KB

Grant External Account Permissions to Modify Delegates

This HTA applet allows you to grant extended AD permissions to a specific user. I use it to assign permissions to the Associated External Account of an AD user rights to modify their own delegates.

I found what values I needed by configuring a single user with permissions, then using Richard's DACL export script to dump that user. I then modify the script (see line 248) to match the permissions I want to grant.

' Template: AddAce(TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType)

The applet runs faster on the DC, but is usable on my local workstation.

AttachmentSize
SetDelegatePerms.hta12.8 KB

Changing the Exchange Organization after Installation.

Today I had the honor of working with a company after a catastrophic failure of their Exchange server. One day their hardware was working just fine, the next the server will no longer boot and Exchange is down.

As part of the repair, I installed Exchange 2000 on a new server, and attempted to mount the databases from the mirrored drive. After a few manual uninstalls of Exchange and the the typical passes with ESEUTIL to repair the dirty shutdown the database was coming up clean, but still would not mount.

Checking the Application event log, I found that the server was built in the wrong Exchange Organization. Ugh! As Microsoft states repeatedly, to change the Org, one must reinstall Exchange. In Exchange 5.5 it was so bad, that we would worry about the case of the Organization name when adding new servers to an Exchange site.

That was COMPANY and not Company for the Organization name, right??

In 2000 and 2003, I've always understood that this had not changed. Plan ahead and do it right the first time. So, I started an uninstall of Exchange 2000 off this client's server while scouring Technet and Google for a better solution. Of course, as soon as I started the uninstall, I found that Exchange will NOT uninstall because it sees mailboxes are still on the server. Despite not successfully mounting, it must have partially mounted the database and Exchange now thinks they are on the server.

Using the Manual uninstall procedure again, I remove Exchange one more time, do another reinstall, but this time it also fails. Exchange never asked me to change the Organization as it is still registered in AD. Oh well. That's when I found this tool. LegacyDN.

Like RegEdit, this tool has tons of disclaimers:

Never use [name of tool] on a production database, never use unless you have backups, never use on unless you have PSS on hold on the phone and we tell you to run it..

So, I closed my eyes, crossed my fingers and double clicked on it. By default it comes up in read-only mode. I immediately see that it found the First Administrative Group on the server. Clicking on the fields do nothing, but I can see I have hope. So I close it, and reopen it in /FORCEWRITE mode. Click and the Organization field populates. I replace the text with the correct entry, click Update, wait 30 seconds and "The Organization has been updated successfully.". I imagine that my 30 second wait was in part to only having 8 mailboxes in this information store. If this had been a store with a couple hundred or thousand mailboxes, this process may have taken much longer.

Now the database mounted successfully and all is happy. The users can send and receive email without issue. Next, migrate them to Exchange 2003...

Some useful references.

DST: Get DN for Exchange Calendar Update tool

When running through the latest version of the Exchange calendar update process, it has you assign permissions to all mailboxes on the server. To modify all the mailboxes, you need to provide a list of distinguished names (DN) for each mailbox. Unfortunately this is not simply the DistiguishedName field that you would query from AD, but the LegacyDN entry. You need to query the Exchange environment to get this information.

The following script, I pulled from various sources (primarily my Advanced VBScript book off my desk). It echos the DN to the screen, and also creates a CSV file in the folder it was run from. I did have to run it from the Exchange server, but it may also run from a workstation running the Exchange system admin tools.


dim strComputer
dim objwmiservice
dim propvalue
dim SWBEMLocator
Dim UserName
Dim password
Dim ColItems

strLog="MailboxReport.csv"
Set objFSO=CreateObject("Scripting.FileSystemObject")
Set objFile=objFSO.CreateTextFile(strLog,True)

strComputer = inputbox("What is the name of your Exchange server?")
wscript.echo "Querying " & strComputer

username=""
password=""

Set SWBemlocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMIService = SWBemlocator.ConnectServer(strComputer,"\root\MicrosoftExchangeV2",UserName,Password)
Set colItems = objWMIService.ExecQuery("Select * from Exchange_Mailbox",,48)

for each objitem in colitems   
        wscript.echo objitem.legacydn
        objFile.writeline objitem.legacydn
next
objfile.close

Find an email address in your environment

In my environment, I am always looking up a user's email address, or trying to find out what Exchange server their mailbox is on. That's why I developed the attached script.

It will do a wild-card search against your currently logged on domain to find any account with those values. It searches the Displayname, proxyaddresses and mail fields.

AttachmentSize
FindEmail.zip7.03 KB

Lookup email addresses from CSV in AD

Scenario: I was given a list of 15,000 email addresses and asked if they were still valid in our Exchange environment.

Easy method: I ran a simple VBScript that does an LDAP query against each email address. This worked great, except that it took close to 5 seconds per email address to query our environment. (~20 hrs!) The over-all run time was going to be too extreme.

Next method: Read all entries into a datalist using the tricks from Microsoft Scripting Guys. The script would read each object (primary;proxy) into seperate records, then search each one. This ran for 2 hours before the server logged me off. Even if I deleted entries that I found, it still took too long.

Final method: Read each email address and append it to a string for each letter (for example "administrator@example.com;author@example.com" went in A) accessible via an array. Now I have a 50ish (a..z,0..9,!#$%^) row array containing unsorted lists. The script just needs to find the correct row, and see if the email address exists there.

The entire process took approximately 14-15 minutes. This inclides 12 minutes to read in all 250k email addresses from Active Directory(AD) and then sort them. Processing it creates a NEW csv containing the original line, then appends TRUE or FALSE. If it finds the email address, it puts a TRUE, otherwise it puts FALSE. It does very little clean-up of the email addresses it reads from the CSV, but that could be improved rather easily.

AttachmentSize
Find_Duplicates_in_File_v2.zip2.64 KB

Modify Mailbox Alias field

We recently finished a project updating the naming standard for all our Windows AD accounts. Once completed, I found that approximately 3% of the accounts had the alias field set to this old naming standard. Googled high-and-low, I could not find a simple script to set the alias field. So...

This script reads a text file of account distinguished names, then modifies the mailbox alias (aka mailnickname) field to match the SAMAccountName field. Added protection for accounts without mailboxes associated with them. Found that by setting a mailnickname, mail-enabled the account.

' Script to modify the mailbox alias of all accounts in text file to match SamAcct.
'
Written by Eric Woodford
' Date 11/27/2007
'

Dim mbxAlias
dim samAcct
Dim objfso, tf, ef
Dim strUser, arUser
Dim objUser, strDN
Dim testrun

set objfso = CreateObject("Scripting.FileSystemObject")
'reads from this file
set tf = objfso.OpenTextFile("c:\useraccounts.txt",1)
'
creates this log file
set ef = objfso.CreateTextFile("c:\User-Updates.log",vbtrue)

'set this boolean value to TRUE to it will not modify accounts. Good for testing results.
testrun = true

if testrun Then
     ef.writeline "Starting TEST RUN at: " & Now()
Else
     ef.writeline "Starting Account Conversion at: " & Now()
End If

'
Loop through file
While tf.AtEndOfStream <> True
     strDN= tf.readline

     ' cleanup values from export.
     strDN = trim(replace(replace(Replace(strDN,"\\","\"),"""",""),"'
'","'"))
     If Left(strDN,1) = "
'" then strDN=Mid(strdn,2,Len(strDN))
     If Right(strDN,1) = "'
" then strDN = Mid(strdn,1, len(strdn)-1)

     'don't bother processing if not a distinguished name.
     If instr(strDN,"
CN=")>0 Then
          ef.writeline now() & "
:" & strDN    
          'ef.writeline "
Wanting to set to:" & arUser(1)
          Set objUser = GetObject("
LDAP://"&strDN)                
          samacct = objUser.sAMAccountName
          mbxAlias = objUser.mailnickname

          ' skip if already set, or no mailbox associated with it
          If (LCase(trim(mbxAlias))<> LCase(samacct)) And (mbxAlias<>"
") Then
               ' If these don't match, then the account needs updating.
               ' a little formatting for the report.
               sp = vbtab
               If Len(mbalias) < 6 Then sp = sp & vbtab
               If Len(mbalias) < 12 Then sp = sp & vbtab

               ef.WriteLine "
Alias: "&mbxAlias&sp&" should be: "& LCase(samacct)
               ' This means that the Alias is still set to the old account information.
               If Not testrun Then
                    objUser.mailnickname = samacct
                    objUser.SetInfo
               Else
                    ef.WriteLine "
testrun - values not changed."
               End If                              
          Else
               ' don't bother updating as it is already correct.
               ef.WriteLine "
Alias correct: " & mbxAlias &sp&" is "& LCase(samacct)
          End if          
          Set objuser=Nothing          
     End If
Wend

tf.Close
ef.Close

Powershell Quick report - all smtp email addresses

Attending a class this week for Exchange 2007. The question came up to export all SMTP email addresses for all mailboxes. In the lab environment, I worked up this script.

$data = get-mailbox | %{ $dname = $_.displayname;$em=$_.emailaddresses -replace("smtp:",",");$dname+$em}

I have not tested this in a production environment, so I am not sure what will display for users with other than SMTP email addresses.

Purging a list of Mailboxes from Exchange 2003

The migration process used to move a number of mailboxes created a couple hundred dead mailboxes objects in our environment. Their mailbox information needed to be cleared before their mailboxes could be migrated to the server for the final time. To fix this, I looked into a script. First I found the script at TelnetPort25, here. This script goes through the entire environment and purges all deleted and non-system mailboxes. This would work great, but querying an environment with literally thousands of mailboxes is a daunting task.

That's when I found this script that would simply dump all the deleted-not-purged mailboxes on a specific server. Running this script generates a CSV file with their displayname, and some additional information. I copied the displayname field out of Glen's script and pasted to a text file to use and re-wrote Telnet's to fit my purpose.

Note: uncomment the line ' objExchange_Mailbox.Purge when you feel the script is working correctly.

 
'===================================================='
' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 3.1
'

' NAME: PurgeSelectedMailboxes.VBS
'

' AUTHOR:  Eric Woodford - <a href="mailto:EricWoodford@gmail.com">EricWoodford@gmail.com</a>
'
DATE  : 3/10/2008
'
'
COMMENT: Purge listed mailboxes on this Exchange server.
' Must be ran from the server.
'

'====================================================

Const cWMINameSpace = "root/MicrosoftExchangeV2"
Const cWMIInstance = "Exchange_Mailbox"

strComputerName = "."
strPathToCSV = "c:\"
strListofNames = "names.txt"

Set objfso = CreateObject("scripting.filesystemobject")
Set infile = objfso.opentextfile(strPathtoCSV&"\"&strListofNames,1)

Set wmiConn = GetObject("WinMgmts:{impersonationLevel=impersonate}!\\" & strComputerName & "\root\microsoftexchangev2")

If Err.Number <> 0 Then
  WScript.Echo "Cannot connect to the Exchange WMI Namespace"
  Wscript.Quit
End If

haltloop = false
DO While (not inFile.atendofstream)
        strUserDisplayName = inFile.readline
        WScript.Echo strUserDisplayName
        strWQL = "SELECT * FROM Exchange_Mailbox WHERE MailboxDisplayName = '
" & strUserDisplayName & "'"
        '
filter collection to only selected names
        WScript.Echo "  Searching... Please wait"
        Set wmiColl = wmiConn.ExecQuery(strWQL)
        WScript.Echo "Found "&wmiColl.count & " matching mailboxes"
       
        For Each objExchange_Mailbox In wmiColl
                WScript.Echo "Processing: " & strUserDisplayName
                ' objExchange_Mailbox.Purge
        next   
Loop  
infile.close
Set wmiColl = Nothing
Set objWMIExchange = Nothing
set objfso = Nothing   


Wscript.Echo "Script Completed"

Tool to Export DL Membership

Here is a small HTA applet that I have built to export the membership of various groups in Windows Active Directory. It provides some basic filtering (owner, specific OU, name contains), plus 3 modes of export, XLS, CSV, or HTML to screen. Beware, if you have office 2007, XLS is XLSX format.

To run this in your environment, it will need to be modified:
line 27 & 28

 strHTML=strhtml&"<option value=""LDAP://dc=local,dc=corp"" >All OUs"
strHTML=strhtml&"<option value=""LDAP://ou=sub,dc=local,dc=corp"" >This SUB OU Only"

line 55 & 56

strHTML=strhtml&"<option value=""LDAP://dc=local,dc=corp"" >All OUs"
strHTML=strhtml&"<option value=""LDAP://ou=sub,dc=local,dc=corp"" >This SUB OU Only"

CSV mode gives the best detail as XLS has a 255 character limit on single fields.

Just fixed issue where it required you to pick a subOU in order to continue.

AttachmentSize
DL Export Report.zip6.3 KB

Find ALL DLs that a specific person manages

Friend is working on the dirty deed of removing a series of accounts from AD. As part of that clean-up he is to find all the distribution lists that each account is assigned manager on. Using the Quest ActiveRoles Powershell tools, you can quickly find these unfortunate people using:

$selectUser = Get-QADUser "John Doe"
Get-QADGroup -SizeLimit 0  -ldapFilter '(&(mail=*)(managedby=*))' | where {$_.managedby -eq $selectUser}  | select displayname, managedby

Using a Batch to Exmerge a Recovery Storage Group - Mailbox from Exchange 2003

I am working on a project to recover 30 individual days of email from a clients mailbox. This requires me to restore 30 days worth of backups to the Recovery Storage Group(RSG) on a specific server. I have quickly grown tired of selecting the name from the giant Exmerge list and worked out how to use a batch file to run Exmerge against the RSG.

Part 1: Exmerge.ini

[Exmerge]
MergeAction=0
RestoreDB=1
FileContainingListOfDatabases=database.txt
SourceServerName=<Exchange Server Name>
FileContainingListOfMailboxes=Mailboxes.txt
CopyDeletedItemsFromDumpster=1
DataDirectoryName=D:\EXMERGEDATA
LogFileName=ExMerge.log

Part 2: database.txt

CN=SG1-PRIV1,CN=RECOVERY STORAGE GROUP

Part 3: mailboxes.txt

/o=<Organization Name>/ou=First Administrative Group/cn=Recipients/cn=<MailboxAlias>
/o=<Organization Name>/ou=First Administrative Group/cn=Recipients/cn=<MailboxAlias2>

Part 4: the Batch file (exportMbx.bat)

exmerge.exe -b -f exmerge.ini

I've now put a shortcut to the bat file on my desktop and double-click it after the restore completes. If I could only find a script that would then dismount the database, mark it for overwrite and start a new restore from the server, I'd be done! Unfortunately, I've been told by Microsoft you can't script against the RSG, so still got a bunch of clicks for each day.

Back to work...

VBScript- Create Distribution Groups (DL) from CSV

I needed a quick script to create a series of distribution lists on an Exchange environment. I thought, "Cool, a chance to flex my PowerShell muscles!" From that I found new-qadgroup from the quest tools set and new-distributiongroup from the Exchange tools. After quite a bit of muddling around, I was never able to recreate my script.

Requirements I was trying to meet:

  1. Read all data from a CSV file (easy import-csv)
  2. Create a new DL from each line in the CSV (| %{new-distributiongroup -name $_.name}
  3. Populate each list with memers found in the members column (this was semi-colon seperated).
  4. Populate ExtensionAttribute3 with a common value 'FINANCE DLs'. This is used by our Dynamic Address Book views.
  5. Set limit of max message size sent to DL
  6. Set who was able to send to this DL (groups and people)
  7. Set SMTP and Proxy SMTP email addresses.

Unfortunately, after working on the first 3-4 items, I was stumped. VBScript failed me on a number of these, just in the fact that it's not widely published and a few answers varied. So, here is what I developed. The script fails when adding more than 1 additional proxy address, otherwise it worked for all my other tests.

(Sorry for the wrappage..)

'=====================================================
'

' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 3.1
'

' NAME: CreateDL.VBS
'

' AUTHOR: Eric Woodford
'
DATE  : 7/25/2008
'
'
COMMENT: Script is designed to create fully populated distribution lists.
'          The data is pulled from a CSV file.
'
         Assigned fields are:
'               Display Name,
'
              Alias,
'               SMTP Email address,
'
              Proxy SMTP addresses,
'               Accept Messages from,
'
              Maximum Accepted message size (KB - integer format please)
'               Members of the group
'
                           
' Known issue: Accounts with more than 1 proxy address mail fail to load correctly. Still working out the details.  
'
ProxyAddresses - <a href="http://www.eggheadcafe.com/forumarchives/scriptingVisualBasicscript/Aug2005/post23622005.asp
'=====================================================

Const"
title="http://www.eggheadcafe.com/forumarchives/scriptingVisualBasicscript/Aug2005/post23622005.asp
'=====================================================

Const"
>http://www.eggheadcafe.com/forumarchives/scriptingVisualBasicscript/Aug2...</a> ForReading = 1, ForWriting = 2, ForAppending = 8
Const DLGroupEA3 = "Finance DLs"
Const GroupOU = "OU=Finance Users,"
Const CSVFilePath = "C:\Finance_DistributionLists.csv"
Const LogFIlePath = "C:\CreateDL.LOG"

Set fso = CreateObject("scripting.filesystemobject")
Set myCSV = fso.opentextfile(CSVFilePath, ForReading)
Set MyLogFile = fso.opentextfile(LogFIlePath, ForWriting, True)

Do While Not MyCSV.AtEndOfStream
        strCSVLine = myCSV.Readline
        If InStr(strCSVLine,"@")>0 Then ' if it contains a SMTPEmail Address, it must be valid (not a header).
                arrStrUser = Split(strCSVLine,",")
                strAlias = arrStrUser(1)
                strDisplayName = arrStrUser(0)
                strSMTP = arrStrUser(2)
                strMembers = arrStrUser(3)
                strAcceptFrom  = arrStrUser(4)
                IntMaxMsgSize = cint(arrStrUser(6))            
                CreateDistGroup strAlias,strDisplayName, strSMTP ,strAcceptFrom, IntMaxMsgSize
        End If
Loop
MyLogFile.Writeline "Adding Users"

Set myCSV = fso.opentextfile(CSVFilePath, ForReading)          
Do While Not MyCSV.AtEndOfStream
        strCSVLine = myCSV.Readline
        If InStr(strCSVLine,"@")>0 Then '
if it contains a SMTPEmail Address, it must be valid (not a header).
                arrStrUser = Split(strCSVLine,",")
                strAlias = arrStrUser(1)
                strMembers = arrStrUser(3)
                AddGroupMembers strAlias, strMembers
        End If
loop

MyLogFile.close
MyCSV.Close


Sub CreateDistGroup(strAlias, strDisplayname, strSMTP,  strAcceptMsgsFrom, intMaxSizeKB )
Dim strGroup, strDNSDomain
Dim objOU, objGroup, objUser

        Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = &h8
        Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000
        Const ADS_GROUP_TYPE_GLOBAL_GROUP = &h2
       
        Const ADS_PROPERTY_CLEAR = 1
        Const ADS_PROPERTY_UPDATE = 2
        Const ADS_PROPERTY_APPEND = 3
        Const ADS_PROPERTY_DELETE = 4

        Set objRootDSE = GetObject("LDAP://RootDSE")
        strDNSDomain = objRootDSE.Get("DefaultNamingContext")
        Set objOU = GetObject("LDAP://" & GroupOU & strDNSDomain )
        strNewGpLong = "CN=" & strAlias
        Err.Clear
        On Error Resume Next
        Set testGroup = GetObject ("LDAP://"&strNewGpLong&","& GroupOU & strDNSDomain)
        If Err <> 0 Then
                MyLogFile.Writeline "creating: " & strDisplayname &"("&strAlias&")"
                Set objGroup = objOU.Create("Group",strNewGpLong)
                objGroup.Put "sAMAccountName", strAlias
        Else
                MyLogFile.Writeline strDisplayname & " already exists"
        End If
        objGroup.put "Name", Replace(StrDisplayName," ","")    
        objGroup.Put "displayname", strDisplayname
        objGroup.Put "groupType", ADS_GROUP_TYPE_GLOBAL_GROUP  
        objGroup.put "extensionAttribute3", DLGroupEA3
        if intMaxSizeKB > 0 then objGroup.put "delivcontlength", intMaxSizeKB
        objGroup.mailenable
        objGroup.setInfo
        objGroup.put "dLMemSubmitPerms", "cn="&strAcceptMsgsFrom&","&GroupOU & strDNSDomain    
        if instr(strSMTP,";")=0 Then
                strNewSMTP = mid(strSMTP,6)
                'strNewSMTP = strSMTP
                MyLogFile.Writeline "Adding : " & strNewSMTP
                objGroup.Put "mail", strNewSMTP
                objGroup.put "targetAddress", strNewSMTP
                objGroup.PutEx ADS_PROPERTY_UPDATE, "ProxyAddresses", array(strSMTP)
                objGroup.SetInfo
        Else
                arrSMTP= Split(StrSMTP,";")
                strNewSMTP = mid(arrSMTP(0),6)
                MyLogFile.Writeline "Adding : " & strNewSMTP
                objGroup.Put "mail", strNewSMTP
               
                '
http://support.microsoft.com/kb/q260251/
                x = 0
                For Each sAddress In arrSMTP
                        MyLogFile.Writeline "+" & sAddress
                        If x = 0 Then
                                objGroup.PutEx ADS_PROPERTY_UPDATE, "ProxyAddresses", array(sAddress)
                                objGroup.put "targetAddress", sAddress
                                x = x + 1
                        Else
                                objGroup.PutEx ADS_PROPERTY_APPEND, "ProxyAddresses", array(sAddress)
                        End if
                        objGroup.SetInfo
                Next                   
        End If
        objGroup.setInfo
        Set objGroup = Nothing
       
End Sub

Sub AddGroupMembers (strAlias, strMembers)
On Error Resume next
        Set objRootDSE = GetObject("LDAP://RootDSE")
        strDNSDomain = objRootDSE.Get("DefaultNamingContext")
        Set objGroup = GetObject ("LDAP://cn="&strAlias&","& GroupOU & strDNSDomain)
        If strMembers <> "" Then
                arrMembers = Split(strMembers,";")     
                For Each struser In arrMembers  
                        Err.Clear              
                        objGroup.Add("LDAP://cn="&strUser&","&GroupOU & strDNSDomain)
                       
                        If Err = 0 Then
                                MyLogFile.Writeline "Successfully added: " & strUser & " -> " & strAlias
                        Else
                                MyLogFile.Writeline "Failed : " & strUser & " -> " & strAlias
                        End If                         
                next
        End if         
End Sub