Utility Libraries for Exchange Scripting

Originally published July 11, 2006

 

I write many many many Exchange scripts. There are some things that are common in Exchange script - you need to get mailbox sizes, or a list of all the servers in an administrative group, or a list of all Exchange servers, etc. So, I ended up encapsulating all of those routines into a set of include files that I can easily use in my vbscripts. Most of these can easily be adapted for ASP usage with IIS (I've done so and made that easy - trust me).

My last post Finding disk space used by Exchange requires a number of these libraries.

Typically, I have a folder where I do all my scripting work (I typically call it something really original such as “C:\Scripts”). Below that I have an additional folder that I name “lib” for “library files” (you can tell that I originally worked in Unix and mainframes) where I place all of my include files. I have a short commentary about each file:

FILESTART: lib\constants.vbs

' This file contains various constants and pseudo-constants used by many
' of the other routines and other scripts I write. The ADS_* and wbem*
' constants are Windows constants. All of the others are used throughout
' various programs.

' Constants we need for ADSI calls
Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
Const ADS_PROPERTY_APPEND = 3
Const ADS_PROPERTY_DELETE = 4
Const ADS_ACETYPE_ACCESS_ALLOWED = 0
Const ADS_ACEFLAG_INHERIT_ACE    = &H2

' Constants we need for WBEM calls
Const wbemFlagReturnImmediately = &H10
Const wbemFlagForwardOnly = &H20

' Constants we need for configuration
Const OU_HOSTING = "OU=Hosting"  ' the OU where I put customer OU's
Const ExchServer = "ORANGE"  ' the exchange server whose default mailbox store I'll use
Const Trustee    = "Domain Admins" ' an extra ACL to add to the mailbox

' Are we a web application or not?
Const bWebApplication = False

Dim bDebug    ' verbose output (used to be a constant)
bDebug = False

FILESTART: lib\ado.vbs

' This file contains routines that make using ADSI easier

Dim objCom ' the global ADO command object
Dim objConn ' the global ADO connection object
Dim Rs  ' the global ADO resultset object
'
' InitializeADSI
' Purpose:
'  Initialize the global ADO objects used for making
'  ADSI queries.
'
' Inputs:
'  None
'
' Outputs:
'  None
'
' Requires:
'  N/A
'
Sub InitializeADSI
 Set objCom  = CreateObject ("ADODB.Command")
 Set objConn = CreateObject ("ADODB.Connection")

 ' Open the connection.
 objConn.Provider = "ADsDSOObject"
 objConn.Open "ADs Provider"
End Sub
'
' DoneWithADSI
' Purpose:
'  Clean up the global ADO objects.
'
' Inputs:
'  None
'
' Outputs:
'  None
'
' Requires:
'  Must be called after InitializeADSI
'
Sub DoneWithADSI
 objConn.Close

 Set objCom  = Nothing
 Set objConn = Nothing
End Sub
'
' DoLDAPQuery
' Purpose:
'  Execute a paged LDAP query, using the
'  global ADO objects.
'
' Inputs:
'  strLDAPQuery - the LDAP query to execute
'
' Outputs:
'  resultSet - the result set from the query
'
' Requires:
'  Must be called after InitializeADSI
'
Sub DoLDAPQuery (strLDAPQuery, resultSet)
 dp "LDAP query: " & strLDAPQuery

 objCom.ActiveConnection         = objConn
 objCom.Properties ("Page Size") = 1000
 objCom.CommandText              = strLDAPQuery

 Set resultSet = objCom.Execute
End Sub
'
' FinishLDAPQuery
' Purpose:
'  Clean up the result set after an LDAP query.
'
' Inputs:
'  resultset - a result set from DoLDAPQuery
'
' Outputs:
'  None
'
' Requires:
'  Must be called after DoLDAPQuery
'
Sub FinishLDAPQuery (resultSet)
 resultSet.Close

 Set resultSet = Nothing
End Sub

FILESTART: lib\report.vbs

' This file contains routines that make it easy to output
' debugging information and to switch back and forth
' between console and web page output. I get so tired
' of typing “wscript.echo blah blah blah“ so many times...

'
' CleanItUp
' Purpose:
'  When using these reporting routines in an ASP or HTA
'  application, this routine properly translates some
'  special characters for output/display purposes.
'
' Inputs:
'  str - the string to be cleaned up
'
' Outputs:
'  Function value - the cleaned up string
'
' Requires:
'  bWebApplication from constants.vbs
'
Function CleanItUp (str)
 If bWebApplication Then
  Dim str1

  str1 = Replace (str, "<", "&lt;")
  str1 = Replace (str1, ">", "&gt;")

  CleanItUp = str1
 Else
  CleanItUp = str
 End If
End Function
'
' e
' Purpose:
'  An "echo" routine to output information to the end-user
'
' Inputs:
'  str - The string to be output
'
' Outputs:
'  None
'
' Requires:
'  bWebApplication from constants.vbs
'
Sub e (str)
 If bWebApplication Then
  response.write CleanItUp (str) & "<br>"
 Else
  wscript.echo str
 End If
End Sub
'
' p
' Purpose:
'  An "echo" routine that starts a new paragraph to output
'  information to the end-user
'
' Inputs:
'  str - The string to be output
'
' Outputs:
'  None
'
' Requires:
'  bWebApplication from constants.vbs
'
Sub p (str)
 If bWebApplication Then
  response.write "<p>" & CleanItUp (str) & "<br>"
 Else
  wscript.echo vbCrLf & str
 End If
End SUb
'
' dp
' Purpose:
'  A "debug.print" routine to output information to the end-user
'
' Inputs:
'  str - The string to be output
'
' Outputs:
'  None
'
' Requires:
'  bDebug from constants.vbs
'
Sub dp (str)
 If bDebug Then e CleanItUp (str)
End Sub

Sub ErrorReport
 e "***** Error: " & Err.Description & " (0x" & Hex (Err.Number) & ")"
End Sub

Sub WarnReport
 e "***** Warning: " & Err.Description & " (0x" & Hex (Err.Number) & ")"
End Sub

FILESTART: lib\systeminfo.vbs

' This file contains basic routines that acquire information about the
' the Exchange organization (its name and its default SMTP address)
' as well as the computer that the script is being run upon (its Windows
' domain and the computer name)

Dim strNetBIOSDomain ' the NetBIOS domain this program is running in
Dim strNetBIOSComputer ' the NetBIOS name of the computer this program is running on
Dim strConfigNC  ' the configuration naming context of this domain
Dim strDomainNC  ' the domain naming context of this domain
Dim strOrgDN  ' the distinguished name of the Exchange organization
Dim strDefaultDomain ' the default SMTP domain for the Exchange organization
'
' GetSystemInfo
' Purpose:
'  Determine the necessary system variables to be
'  able to make queries from Active Directory. Also,
'  initialize ADO/ADSI global variables, and get
'  Exchange organization information.
'
' Inputs:
'  None
'
' Outputs:
'  Causes many global variables to be initialized
'
' Requires:
'  None
'
Function GetSystemInfo
 Dim objSystemInfo, objWSHNetwork

 Call InitializeAD

 ' get the NetBIOS domain name
 Set objSystemInfo = CreateObject ("ADSystemInfo")
 strNetBIOSDomain = objSystemInfo.DomainShortName
 dp "strNetBIOSDomain: " & strNetBIOSDomain
 Set objSystemInfo = Nothing

 ' get the NetBIOS computer name
 Set objWSHNetwork = CreateObject ("WScript.Network")
 strNetBIOSComputer = objWSHNetwork.ComputerName
 dp "strNetBIOSComputer: " & strNetBIOSComputer
 Set objWSHNetwork = Nothing

 Call InitializeADSI

 If GetOrganizationInformation Then
  Call ClearSystemInfo
  GetSystemInfo = True
  Exit Function
 End If

 Call GetDefaultSMTPDomain

 GetSystemInfo = False
End Function
'
' ClearSystemInfo
' Purpose:
'  Does the necessary cleanup to exit the program.
'
' Inputs:
'  None
'
' Outputs:
'  None
'
' Requires:
'  None
'
Sub ClearSystemInfo
 Call DoneWithADSI
End Sub
'
' InitializeAD
' Purpose:
'  Obtain the naming context strings for the current Active
'  Directory domain.
'
' Inputs:
'  None
'
' Outputs:
'  None
'
' Requires:
'  None
'
Sub InitializeAD
 Dim objRootDSE

 ' Get the forest root directory services entry object
 Set objRootDSE = GetObject ("LDAP://RootDSE")

 ' Exchange information is stored in the Configuration tree of the forest root
 strConfigNC = objRootDSE.Get ("configurationNamingContext")

 ' this gives us the DN to the forest root
 strDomainNC = objRootDSE.Get ("defaultNamingContext")

 dp "Configuration Naming Context: " & strConfigNC
 dp "Domain Naming Context: " & strDomainNC

 Set objRootDSE = Nothing
End Sub
'
' GetOrganizationInformation
' Purpose:
'  Set the global variable strOrgDN which contains the
'  distinguished name of the Exchange organization, which
'  is based in the configuration container.
'
' Inputs:
'  None
'
' Outputs:
'  Sets the global strOrgDN variable
'
' Requires:
'  strConfigNC from InitializeAD
'  All the ADO routines
'
Function GetOrganizationInformation
 Dim strQuery

 GetOrganizationInformation = False

 ' Build a query to find the Exchange organization.
 strQuery = "<LDAP://CN=Microsoft Exchange,CN=Services," & strConfigNC & ">;" & _
  "(objectCategory=msExchOrganizationContainer);" & _
  "name,distinguishedName;" & _
  "onelevel"

 strOrgDN = ""

 Call DoLDAPQuery (strQuery, Rs)

 ' If there are any results, there will only be one result. There
 ' may only be one Exchange organization per Active Directory forest.
 e "Exchange Organization Name: " & Rs.Fields ("name")
 dp "Organization DN: " & Rs.Fields ("distinguishedName")

 strOrgDN = Rs.Fields ("distinguishedName")

 Call FinishLDAPQuery (rs)

 If Len (strOrgDN) = 0 Then
  e "Cannot find Exchange organization information"
  GetOrganizationInformation = True
 End If
End Function
'
' GetDefaultSMTPDomain
' Purpose:
'  Obtain the default SMTP domain for the Exchange organization.
'  This is normally the same as the forest root domain (until
'  changed by an Exchange administrator).
'
' Inputs:
'  None
'
' Outputs:
'  Set the global strDefaultDomain
'
' Requires:
'  strOrgDN from GetOrganizationInformation
'
Sub GetDefaultSMTPDomain
 Dim strAddress   ' string
 Dim strAddresses ' collection of addresses
 Dim objPolicy    ' reference to Default Recipient Policy

 strDefaultDomain = ""

 Set objPolicy = GetObject ("LDAP://CN=Default Policy,CN=Recipient Policies," & strOrgDN)
 strAddresses  = objPolicy.Get ("gatewayProxy")

 ' strAddresses contains all the addresses specified on the
 ' E-Mail Addresses tab of the default recipient policy

 For Each strAddress in strAddresses
  If Left (strAddress, 5) = "SMTP:" Then
   strDefaultDomain = Right (strAddress, Len (strAddress) - 6) ' strip SMTP:@
  End If
  dp "Email address suffix: " & strAddress
 Next

 ' Report our results
 e "Default SMTP address for organization: " & strDefaultDomain

 Set strAddresses = Nothing
 Set objPolicy = Nothing
End Sub

FILESTART: lib\queries.vbs

' This file contains the routines to find out about servers, storage groups, and
' stores in an Exchange organization. Each individual routine is preceeded
' by individual documentation.

' all lists are semi-colon separated

' a list of all the servers in the organization
' and a parallel list containing their distinguished names
Dim strServerList, strServerListDN

' a list of all OAL's in the organization
' and a parallel list containing their adminText attribute
Dim strOALList, strAdminList

' a list of all administrative groups in the org
' and a parallel list containing their distinguished names
Dim strAGroupList, strAGroupListDN

' a list of all servers in an admin group
Dim strServerAGList

' a list of all storage groups on a server
' and a parallel list containing their distinguished names
Dim strServerSG, strServerSGDN

' a list of all the stores in a storage group (by distinguished name)
' and a parallel list of their types (public or private)
Dim strStoreDN, strStoreType
'
' GetAllServers
' Purpose:
'  Get a list of all servers in the Exchange organization, and
'  prepare two semi-colon separated lists - one of the short
'  server name and one of the server distinguished name.
'
' Inputs:
'  None
'
' Outputs:
'  Sets the value of the global variables strServerList and
'  strServerListDN
'
' Requires:
'  strOrgDN from GetOrganizationInformation
'
Sub GetAllServers
 Dim strQuery

 ' Get the list of all servers within the organization
 strQuery = "<LDAP://" & "CN=Administrative Groups," & strOrgDN & ">;" & _
  "(objectCategory=msExchExchangeServer);" & _
  "name,cn,distinguishedName;" & _
  "subtree"

 strServerList   = ""
 strServerListDN = ""

 Call DoLDAPQuery (strQuery, Rs)

 p "All Exchange Servers in forest " & strDomainNC
 While Not Rs.EOF
  ' output the current server found
  dp "Server CN: " & Rs.Fields ("cn")
  e  vbTab & "Server Name: " & Rs.Fields ("name")
  dp "Server DN: " & Rs.Fields ("distinguishedName")

  strServerList   = strServerList   & ";" & Rs.Fields ("name")
  strServerListDN = strServerListDN & ";" & Rs.Fields ("distinguishedName")

  Rs.MoveNext
 Wend

 strServerList = Mid (strServerList, 2)
 strServerListDN = Mid (strServerListDN, 2)

 Call FinishLDAPQuery (Rs)

 ' Report our results
 e " "
 dp "strServerList = " & strServerList
 dp "strServerListDN = " & strServerListDN
 dp " "
End Sub
'
' GetAllOfflineAddressLists
' Purpose:
'  Prepare two semi-colon separated lists, one containing the
'  offline address lists present in the Exchange organization,
'  and the other containing the adminDescription field for the
'  OAL (used to store business logic information).
'
' Inputs:
'  None
'
' Outputs:
'  Set the value of the global variables strOALList and
'  strAdminList.
'
' Requires:
'  strOrgDN from GetOrganizationInformation
'
Sub GetAllOfflineAddressLists
 Dim strQuery
 Dim str

 ' Get the list of all offline address lists within the organization
 strQuery = "<LDAP://" & "CN=Offline Address Lists,CN=Address Lists Container," & strOrgDN & ">;" & _
  "(objectCategory=msExchOAB);" & _
  "name,adminDescription;" & _
  "onelevel"

 strOALList = ""
 strAdminList = ""

 Call DoLDAPQuery (strQuery, Rs)

 dp "All OALs in DN " & "CN=Offline Address Lists,CN=Address Lists Container," & strOrgDN
 While Not Rs.EOF
  str = Rs.Fields ("adminDescription")
  If IsNull (str) or (Len (str) = 0) Then
   str = "<null>"
  End If

  strOALList   = strOALList   & ";" & Rs.Fields ("name")
  strAdminList = strAdminList & ";" & str

  Rs.MoveNext
 Wend

 strOALList = Mid (strOALList, 2)
 strAdminList = Mid (strAdminList, 2)

 Call FinishLDAPQuery (Rs)

 ' Report our results
 dp "strOALList = " & strOALList
 dp "strAdminList = " & strAdminList
End Sub
'
' GetAdministrativeGroupInformation
' Purpose:
'  Prepare a semi-colon separated list containing all administrative
'  groups in the Exchange organization.
'
' Inputs:
'  None
'
' Outputs:
'  Set the value of the global variable strAGroupList
'
' Requires:
'  strOrgDN from GetOrganizationInformation
'
Sub GetAdministrativeGroupInformation
 Dim strQuery

 ' Get the list of all Administrative Groups within the organization
 strQuery = "<LDAP://CN=Administrative Groups," & strOrgDN & ">;" & _
  "(objectCategory=msExchAdminGroup);" & _
  "name,cn,distinguishedName;" & _
  "onelevel"

 strAGroupList = ""
 strAGroupListDN = ""

 Call DoLDAPQuery (strQuery, Rs)

 While Not Rs.EOF
  ' output the current administrative group found
  dp "Admin Group CN: " & Rs.Fields ("cn")
  dp "Administrative Group Name: " & Rs.Fields ("name")
  dp "Admin Group DN: " & Rs.Fields ("distinguishedName")

  strAGroupList = strAGroupList & ";" & Rs.Fields ("name")
  strAGroupListDN = strAGroupListDN  & ";" & Rs.Fields ("distinguishedName")

  Rs.MoveNext
 Wend

 strAGroupList = Mid (strAGroupList, 2)
 strAGroupListDN = Mid (strAGroupListDN, 2)

 Call FinishLDAPQuery (Rs)

 ' Report our results
 dp "strAGroupList = " & strAGroupList
End Sub
'
' GetServersForAdministrativeGroup
' Purpose:
'  Prepare a semi-colon separated list of all servers in the
'  Exchange organization. This shows an alternate method of
'  obtaining the GetAllServers list, doing a "onelevel" search
'  instead of a "subtree" search. However, since the query uses
'  an indexed attribute, objectCategory, the added complexity
'  does not buy any performance benefit.
'
' Inputs:
'  None
'
' Outputs:
'  Set the value of the global variable strServerAGList
'
' Requires:
'  strOrgDN from GetOrganizationInformation
'
Sub GetServersForAdministrativeGroup
 ' Get the list of servers for each administrative group
 ' (this is provided just in case you are interested)
 Dim strQuery, strServerAGList
 Dim arr
 Dim i

 arr = Split (strAGroupList, ";")

 strServerAGList = ""

 For i = LBound (arr) To UBound (arr)
  e "Exchange Servers for Administrative Group: " & arr (i)
  strQuery = "<LDAP://" & _
   "CN=Servers,CN=" & arr (i) & ",CN=Administrative Groups," & strOrgDN & ">;" & _
   "(objectCategory=msExchExchangeServer);" & _
   "name,cn,distinguishedName;" & _
   "onelevel"

  Call DoLDAPQuery (strQuery, Rs)

  While Not Rs.EOF
   ' output the current server found
   dp "Server CN: " & Rs.Fields ("cn")
   e "Server Name: " & Rs.Fields ("name")
   dp "Server DN: " & Rs.Fields ("distinguishedName")

   strServerAGList = strServerAGList & ";" & Rs.Fields ("name")

   Rs.MoveNext
  Wend

  strServerAGList = Mid (strServerAGList, 2)

  Call FinishLDAPQuery (Rs)

  dp "Exchange server list for AG " & arr (i) & ": " & strServerAGList
 Next
End Sub
'
' GetStoresForStorageGroup
' Purpose:
'  Prepare a semi-colon separated list of all the message stores
'  in a given storage group. A parallel list containing the type
'  of the storage group is also prepared. This routine uses ADSI
'  enumeration to obtain the list.
'
' Inputs:
'  strStorageGroup - contains the distinguished name of the storage
'  group to be examined.
'
' Outputs:
'  Set the value of the global variables strStoreDN and strStoreType
'
' Requires:
'  None
'
Sub GetStoresForStorageGroup (strStorageGroup)
 Dim objSG, objStore
 Dim strOC, strType

 strStoreDN   = ""
 strStoreType = ""

 Set objSG = GetObject ("LDAP://" & strStorageGroup)

 For Each objStore in objSG
  strOC = objStore.Get ("objectCategory")
  ' turn objectCategory into objectClass
  strType = Left (strOC, Instr (strOC, ",") - 1)
  strType = Replace (Mid (strType, 4), "-", "")

  dp vbTab & "store: " & objStore.Name & _
   " " & strType

  strStoreDN   = strStoreDN   & ";" & objStore.Get ("distinguishedName")
  strStoreType = strStoreType & ";" & strType
 Next

 strStoreDN   = Mid (strStoreDN, 2)
 strStoreType = Mid (strStoreType, 2)

 ' Report results
 dp "store DN's: " & strStoreDN
 dp "store Types: " & strStoreType
End Sub
'
' GetStoresForStorageGroupLDAP
' Purpose:
'  Prepare a semi-colon separated list of all the message stores
'  in a given storage group. A parallel list containing the type
'  of the storage group is also prepared. This routine uses LDAP
'  queries to obtain the list.
'
' Inputs:
'  strStorageGroup - contains the distinguished name of the storage
'  group to be examined.
'
' Outputs:
'  Set the value of the global variables strStoreDN and strStorType
'
' Requires:
'  None
'
Sub GetStoresForStorageGroupLDAP (strStorageGroup)
 Dim strQuery, strType

 strStoreDN   = ""
 strStoreType = ""

 ' public stores first
 strType = "msExchPublicMDB"
 strQuery = "<LDAP://" & strStorageGroup & ">;" & _
  "(objectCategory=msExchPublicMDB);" & _
  "name,cn,distinguishedName;" & _
  "onelevel"

 Call DoLDAPQuery (strQUery, Rs)
 While Not Rs.EOF
  strStoreDN   = strStoreDN   & ";" & Rs.Fields ("distinguishedName")
  strStoreType = strStoreType & ";" & strType

  dp vbTab & "store: " & Rs.Fields ("name") & _
   " " & strType

  Rs.MoveNext
 Wend

 Call FinishLDAPQuery (Rs)

 ' private stores next
 strType = "msExchPrivateMDB"
 strQuery = "<LDAP://" & strStorageGroup & ">;" & _
  "(objectCategory=msExchPrivateMDB);" & _
  "name,cn,distinguishedName;" & _
  "onelevel"

 Call DoLDAPQuery (strQUery, Rs)
 While Not Rs.EOF
  strStoreDN   = strStoreDN   & ";" & Rs.Fields ("distinguishedName")
  strStoreType = strStoreType & ";" & strType

  dp vbTab & "store: " & Rs.Fields ("name") & _
   " " & strType

  Rs.MoveNext
 Wend

 Call FinishLDAPQuery (Rs)

 strStoreDN   = Mid (strStoreDN, 2)
 strStoreType = Mid (strStoreType, 2)

 ' Report results
 dp "store DN's: " & strStoreDN
 dp "store Types: " & strStoreType
End Sub
'
' GetStorageGroupsForServer
' Purpose:
'  Prepare a semi-colon separated list containing the storage
'  groups defined on a specific Exchange server.
'
' Inputs:
'  strServerDN - the distinguished name of the server for
'  which the storage group list is desired.
'
' Outputs:
'  Set the value of the global variables strServerSG and
'  strServerSGDN.
'
' Requires:
'  None
'
Sub GetStorageGroupsForServer (strServerDN)
 Dim strQuery

 strQuery = "<LDAP://" & "CN=InformationStore," & strServerDN & ">;" & _
  "(objectCategory=msExchStorageGroup);" & _
  "name,cn,distinguishedName;" & _
  "onelevel"

 strServerSG   = ""
 strServerSGDN = ""

 Call DoLDAPQuery (strQuery, Rs)

 dp "All storage groups on server " & Left (strServerDN, InStr (strServerDN, ",") - 1)
 While Not Rs.EOF
  ' output the current server found
  dp "Storage Group CN: " & Rs.Fields ("cn")
  dp "Storage Group Name: " & Rs.Fields ("name")
  dp "Storage Group DN: " & Rs.Fields ("distinguishedName")

  strServerSG   = strServerSG   & ";" & Rs.Fields ("name")
  strServerSGDN = strServerSGDN & ";" & Rs.Fields ("distinguishedName")

  Call GetStoresForStorageGroup (Rs.Fields ("distinguishedName"))

  Rs.MoveNext
 Wend

 strServerSG = Mid (strServerSG, 2)
 strServerSGDN = Mid (strServerSGDN, 2)

 Call FinishLDAPQuery (Rs)

 ' Report our results
 dp "All Storage Groups on Server: " & strServerSG
End Sub
'
' GetStorageGroupsForAllServers
' Purpose:
'  This is simply a sample of how to process all of the servers,
'  storage groups, and information stores in a given Exchange
'  organization.
'
' Inputs:
'  None
'
' Outputs:
'  None relevant
'
' Requires:
'  Must be called after GetAllServers.
'
Sub GetStorageGroupsForAllServers
 Dim arr, arrSG
 Dim i, j

 arr = Split (strServerListDN, ";")

 For i = LBound (arr) To UBound (arr)
  Call GetStorageGroupsForServer (arr (i))

  arrSG = Split (strServerSGDN, ";")

  For j = LBound (arrSG) To UBound (arrSG)
   Call GetStoresForStorageGroupLDAP (arrSG (j))
  Next
 Next
End Sub 

Published Tuesday, November 13, 2007 8:33 PM by michael
Filed under: , ,

Comments

Wednesday, May 28, 2008 5:06 AM by cyn3rgy

# re: Utility Libraries for Exchange Scripting

Hi Michael

I changed the SMTP:@ stripping line of the GetDefaultSMTPDomain sub to this :

strDefaultDomain = Right (strAddress, Len (strAddress) - Instr(strAddress,"@")) ' strip SMTP:@

as I found varying recipient policies such as %1g%s@domain.com and stripping 6 chars wasn't working for me. Hope it helps someone...  thanks for sharing :)

Thursday, August 07, 2008 11:25 AM by Michael's meanderings...

# Finding Disk Space Used by Exchange, version 2

In July of 2006, I had a blog entry named Finding Disk Space Used By Exchange , and it was quite well

Tuesday, June 09, 2009 5:30 AM by Reporting Storage Size in Exchange

# Reporting Storage Size in Exchange

Pingback from  Reporting Storage Size in Exchange

Monday, October 12, 2009 3:55 AM by Exchange Stats VBScript « Michael J Hall

# Exchange Stats VBScript &laquo; Michael J Hall

Pingback from  Exchange Stats VBScript  &laquo; Michael J Hall