Friday, January 28, 2005

Displaying what version of Exchange your using (Enterprise or Standard) via Script

Somebody asked me this question this week and what I thought would be quite easy turned out to be a little hard. On a Exchange 2003 box there is a WMI class Exchange_Server that you can use to do this and there is a sample in the Exchange SDK here.

But this WMI class isn’t available in Exchange 2000, The PSS knowledge base offers two solutions one is based on looking for event id 1217 or 1216 in the event log and the other one is to use the Guid from the Uninstall key in the registry and they supply all the Guid's for Exchange 2000 Q296587. Unfortunately there didn’t seem to be the same information available for Exchange 2003. A check of the ExBPA which seems to be using the same method did yield all the GUID'S for Exchange 2003 as well as the SBS versions. The Exbpa actually makes quite a good scripting reference if you have a look at the “ExBPA.Config.xml” config file there’s quite a lot of good information about how they are going about retrieving various pieces of information used in this tool.

So putting this together in a script meant using the StdRegProv WMI class to connect to the registry of each server then going though the keys of the uninstall tree looking for the GUID. I combined this will a little code that queried for all the exchange servers in a domain and also grabbed the serialnumber AD property which contains the Build number and service pack of the Exchange server .And the result is the following script that will show which version of Exchange you are using (Standard, Enterprise, SBS or Eval) and what build number and service pack each server is running. I’ve posted a download copy of the script here

The code looks like

set conn = createobject("ADODB.Connection")
set com = createobject("ADODB.Command")
Set iAdRootDSE = GetObject("LDAP://RootDSE")
strNameingContext = iAdRootDSE.Get("configurationNamingContext")
Conn.Provider = "ADsDSOObject"
Conn.Open "ADs Provider"
svcQuery = "<LDAP://" & strNameingContext & ">;(objectCategory=msExchExchangeServer);name,serialNumber,distinguishedName;subtree"
Com.ActiveConnection = Conn
Com.CommandText = svcQuery
Set Rs = Com.Execute
Wscript.echo "Exchange Servers Versions"
Wscript.echo
While Not Rs.EOF
arrSerial = rs.Fields("serialNumber")
For Each Serial In arrSerial
strexserial = Serial
Next
ExVersion = getExversion(rs.fields("name"))
wscript.echo rs.fields("name") & " " & ExVersion & " " & strexserial
Rs.MoveNext
Wend
Rs.Close
Conn.Close
Set Rs = Nothing
Set Com = Nothing
Set Conn = Nothing

function getExversion(strComputer)
const HKEY_LOCAL_MACHINE = &H80000002
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\default:StdRegProv")

strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Uninstall\"
objReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys

For Each subkey In arrSubKeys
select case ucase(subkey)
case ucase("DB20F7FD-67BC-4813-8808-78F63E89EB56") ExVersion = "Exchange 2000 Standard"
case ucase("775CF3DA-C007-4709-B4CC-CE2239BE2E03") Exversion = "Exchange 2000 Standard"
case ucase("FC6FA539-452D-4a9b-8065-C1FA74B86F83") ExVersion = "Exchange 2000 Standard Evaluation"
case ucase("D3574E0C-360A-44d5-858C-33323C2D79F2") ExVersion = "Exchange 2000 Enterprise"
case ucase("F8567801-906B-439b-8D6A-87BDFEC9BA52") ExVersion = "Exchange 2000 Enterprise"
case ucase("65D9643D-06E8-47d6-865E-80F4CC9BB879") ExVersion = "Exchange 2000 Enterprise"
case ucase("8B102332-6052-4af3-ADFA-35A3DED0506A") ExVersion = "Exchange 2000 Enterprise Evaluation"
case ucase("ee2d3727-33c0-11d2-ab50-00c04fb1799f") ExVersion = "Exchange 2000 Standard SBS"
case ucase("EAE76D62-2691-4883-8BBB-1F2EE6D370D5") ExVersion = "Exchange 2003 Standard"
case ucase("9682A75B-EBD1-4c7d-88F9-13BE236F706C") ExVersion = "Exchange 2003 Standard"
case ucase("9161A261-6ABE-4668-BBFA-AD06B3F642CF") ExVersion = "Exchange 2003 Standard"
case ucase("D8862944-4F8A-429d-9A4F-6F201428FB0C") ExVersion = "Exchange 2003 Standard Evaluation"
case ucase("C160866F-DE53-434f-ADF1-CC42ABBF8778") ExVersion = "Exchange 2003 Standard Evaluation"
case ucase("74F3BB3C-A434-48fa-AAC1-3FC37CD2B0DB") ExVersion = "Exchange 2003 Enterprise"
case ucase("7F4210A8-D3B4-480a-835E-D5DAA0D0B157") ExVersion = "Exchange 2003 Enterprise"
case ucase("4050D45F-9598-44bc-8C07-4C1BBE22EFBB") ExVersion = "Exchange 2003 Enterprise"
case ucase("F95DE19F-CF69-4b03-81B6-9EC050D20D3B") ExVersion = "Exchange 2003 Enterprise"
case ucase("3D5A0E1C-B6DA-42a7-A871-03CD2E30FEA3") ExVersion = "Exchange 2003 Enterprise Evaluation"
case ucase("2B8EC4BD-5638-47e2-8817-1A50B38A828D") ExVersion = "Exchange 2003 Enterprise Evaluation"
case ucase("5717D53E-DD6D-4d1e-8A1F-C7BE620F65AA") ExVersion = "Exchange 2003 Standard SBS"
end select
Next
getExversion = ExVersion
end function

Showing which DC your Exchange Server is using

I found this one the other day while looking for something else but its something that pops up for me now and again. If you want to find out which Domain Controller your Exchange server is currently using you can use the DirectoryServer property from the IExchangeserver Interface with CDOEXM. To use it in a script its just 3 lines

Set iExchSvr = CreateObject("CDOEXM.ExchangeServer")
iExchSvr.datasource.open "Servername"
wscript.echo iExchSvr.DirectoryServer

Thursday, January 20, 2005

Draft DL templates Script

I've been thinking a lot about DL's over the last week or so and have been running a few idea's around about how to use them in different ways. One idea was to create a bunch of DL's by scanning though the sent items folder of a mailbox and looking at any mail that had more then a certain number of recipients. Although this sounded like a good idea when I looked into it further it seemed that these type of emails where never usually just sent to a large number of recipients but rather there was a bunch of people in the To line another bunch being CC and maybe a few BCC'd. So what I though about instead of creating DL's why not just create some template emails that where addressed with all the TO,CC and BCC address's of people you sent these type of emails to and then store all these templates in a folder within the drafts folder.

Out of this idea the following script was born, It uses CDO 1.2 basically because access to the recipients collection of a message is a lot easier when using CDO 1.2. It first checks to see if there is a folder within the drafts folder called DL drafts, if not it creates this folder. After this it creates a collection of the messages in the sent items folder and goes though each one looking for messages with 4 recipients or more. If it finds a messages with more then 4 recipients it then goes though and gets a ordered list of these recipients using a disconnected recordset (this is so I could sort the recipientlist alphabetically and by type). It compares this list with the list of any email already in the DL Drafts folder to ensure no duplicate templates are created. If no duplicates exist it creates the template using the recipientlist from the previous email and sets the subject to a single string list of all the recipients of the email.

So what you end up with is a folder under drafts with a bunch of templates based on your email sending trends. So when you want to send a mail to list of recipients that you know you have sent to before you should already have a template in the drafts folder with the address's setup the way you like . You then just need to change the subject, put your content in and click send. The one problem is this is a one shot template once you have sent it that template is gone. You can rerun the script which is fortunately smart enough not to create duplicates. Another way would be to put a event sink on the folder that would rerun the population script every time a template was used. The other problem is that in the time you sent the last message to the present, one of the address's may have become invalid because a person has left the company or changed their email address.

I not sure how useful this will be but a its little quirky and bit of fun.

I've posted a downloadable copy here the code look like


Public Const CdoDefaultFolderSentItems = 3
Public Const CdoPR_DRAFTS_FOLDER = &H36D70102
Public const adVarChar = 200
set objSession = CreateObject("MAPI.Session")
strProfile = "servername" & vbLf & "mailbox"
objSession.Logon "",,, False,, True, strProfile
Set objInbox = objSession.Inbox
Set objInfoStore = objSession.GetInfoStore(objSession.Inbox.StoreID)
strDraftsEntryID = objInbox.Fields.Item(CdoPR_DRAFTS_FOLDER)
Set objDraftsFolder = objSession.GetFolder(strDraftsEntryID, Null)
set objSentItemsFolder = objSession.GetDefaultFolder(CdoDefaultFolderSentItems)
set ColDraftfolders = objDraftsFolder.folders
bFound = False
Set CdoDraftsFolder = ColDraftfolders.GetFirst
Do While (Not bFound) And Not (CdoDraftsFolder Is Nothing)
If CdoDraftsFolder.Name = "DL Drafts" Then
bFound = True
set colDLDraftmsg = CdoDraftsFolder.messages
Else
Set CdoDraftsFolder = ColDraftfolders.GetNext
End If
Loop
If bFound = False then
Set CdoDraftsFolder = ColDraftfolders.Add("DL Drafts")
Wscript.echo "Create DL Drafts Folder"
set colDLDraftmsg = CdoDraftsFolder.messages
End If
Set objMessages = objSentItemsFolder.Messages
for each objmessage in objMessages
Set colRecips = objmessage.Recipients
if colRecips.Count => 4 then
wscript.echo objmessage.subject
wscript.echo colRecips.Count
strSubject = ""
ifound = false
set rs = createobject("ador.recordset")
rs.fields.append "name", adVarChar, 255
rs.fields.append "AddressType", adVarChar, 255
rs.open
for each objrecip in colRecips
rs.addnew
rs("name") = objrecip.name
rs("AddressType") = objrecip.Type
rs.Update
next
rs.sort = "AddressType,Name"
rs.moveFirst
do until rs.eof
select case rs.fields("AddressType").Value
case 1 strSubject = strSubject & " TO:" & replace(rs.fields("name").Value,"'","")
case 2 strSubject = strSubject & " CC:" & replace(rs.fields("name").Value,"'","")
case 3 strSubject = strSubject & " BCC:" & replace(rs.fields("name").Value,"'","")
end select
rs.moveNext
loop
set rs = nothing
for each objDLmessage in colDLDraftmsg
if objmessage.Recipients.Count = objDLmessage.Recipients.Count then
if strSubject = objDLmessage.Subject then
ifound = True
wscript.echo "Found Skipping"
exit for
end if
end if
next
if ifound = false then
set objnewdlmsg = colDLDraftmsg.add
set colnewdlmsgrecp = objnewdlmsg.Recipients
for each objrecip in colRecips
Set objOneRecip = colnewdlmsgrecp.Add(objrecip.name,objrecip.Address,objrecip.Type,objrecip.AddressEntry.ID)
objnewdlmsg.Subject = strSubject
set objOneRecip = nothing
next
objnewdlmsg.update
set objnewdlmsg = nothing
end if

end if
next


Listing File Sizes with WMI

In my previous post on "Listing the file sizes of all Exchange Stores on all Exchange Servers in a Domain" I used the FSO (file system object) to get the details about the size of exchange store files and drive freespace. Somebody asked a question if there was another way to do this because in their network (as in many others) for security reasons the default admin shares (eg c$ d$) have been disabled.

One way you can go about this is to use WMI and the CIM_DataFile class, If you have Windows 2000 and your store files are above 2 GB you need to make sure you have applied the following hotfix http://support.microsoft.com/?id=820608 for this to work. But using the CIM_DataFile class is actually really easier it actually takes fewer lines of code then using FSO. For example to display the size of priv1.edb on a Exchange box once you know the location of the file its just two lines of code.

Set edbfile = GetObject("winMgmts:!\\servername\root\cimv2:CIM_DataFile.Name='e:\exchsrvr\mdbdata\priv1.edb'")
Wscript.echo "File Size: " & formatnumber(edbFile.fileSize/1073741824,2) & " GB"

To get the freespace on the drive its just as easy using the Win32_LogicalDisk WMI class eg

Set edbdrive = GetObject("winMgmts:!\\servername\root\cimv2:Win32_LogicalDisk.DeviceID='e:'")
Wscript.echo "Freespace: " & formatnumber(edbdrive.freespace/1073741824,2) & " GB"


Although i find FSO does seem a little faster its does offer a good alternative. I've created a WMI version of the Listing the file sizes of all Exchange Stores on all Exchange Servers in a Domain and posted it up here.

Friday, January 14, 2005

Tracking DL-usage with a public folder Event sink

This week I’ve been thinking about issues of trying to track DL usage in a large networks.The idea of tracking distribution list usage by adding a public folder to the DL has been around for a while and offers a good solution. Some problems that do arise from this method is how many folders do you create (eg one per DL) or do you dump then all into one collection spot. The other problem is if someone is BCC’ing the DL its very hard to determine which DL that a message that you tracked was sent to. Back in Exchange 5.5 you used to have a unique event logged (by the MTA which used to perform DL expansion) in the message tracking logs that you could use to work out DL usage. Now in Exchange 2 x DL expansion is handled by the categorizer which has its own tracking log event ID’s but the problem is there’s no difference between a Categorizer event logged for a message and one logged for a DL. The other challenge if you are going to use the Categorizer event on Exchange 2x is that for a categorizer event for that message with DL as a recipient is only going to be logged possibly on two servers. Eg you will have a Categorizer event on the server where the message was originally sent (you’ll have categorizer events for all the unique(non DL) recipients on this server) and you’ll have a categorizer event for the DL on the DL’s expansion server (if a specific expansion server is set otherwise it may only be on the source server if that’s where the DL gets expanded)

So what I decided to do is see if I could create a sink that would look at messages that arrived in my public DL tracking folder. Look at the source where that mail originated and find the home server of the user that sent it. Then connect to the Message Tracking logs on that server and look for all the categorizer “Event 1024” for that particular messageID. Then lookup the recipients in Active Directory to see if they are groups or Query Based DL’s. Then grab the mail address and displayname of all the DL’s that this message was sent to and then update the too address of the email so it contained the names of the DL it was sent to. So no matter even if a DL was only BCC ‘d the Sink would always put that address in the too field so you could tell who it was sent to.

The sink itself uses a combination of CDOEX to open the message grab the messageID, ADSI to find the sending users home server. Then WMI to find the message in the tracking log then ADSI again to search for the recipients in Active Directory to see if they where DL’s and finally CDOEX to update the email. The only real problem I had is that I had to delegate my event sink users view only administration access to my Exchange environments so it had the rights to search the message tracking logs. I’m still thinking about whether this was a good idea or not.

I’ve post a downloadable copy of the sink up here
The code looks like

<SCRIPT LANGUAGE="VBScript">

Sub ExStoreEvents_OnSave(pEventInfo, bstrURLItem, lFlags)
Const EVT_NEW_ITEM = 1
Const EVT_IS_DELIVERED = 8

If (lFlags And EVT_IS_DELIVERED) Or (lFlags And EVT_NEW_ITEM) Then

set msgobj1 = createobject("CDO.Message")
msgobj1.datasource.open bstrURLItem,,3
strComputerName = search_user(replace(replace(msgobj1.fields("urn:schemas:httpmail:fromemail"),">",""),"<",""),2)
if len(strComputerName) <> 0 then
strmessid = replace(replace(msgobj1.fields("urn:schemas:mailheader:message-id"),">",""),"<","")
'Message ID to search for
Const cWMINameSpace = "root/MicrosoftExchangeV2"
Const cWMIInstance = "Exchange_MessageTrackingEntry"
objdlladdress = ""
strWinMgmts = "winmgmts:{impersonationLevel=impersonate}!//" & strComputerName &
"/" & cWMINameSpace
Set objWMIExchange = GetObject(strWinMgmts)
Set listExchange_MessageTrackingEntries = objWMIExchange.ExecQuery("Select *
FROM Exchange_MessageTrackingEntry where entrytype = '1024' and MessageID = '" _
& strmessid & "'",,48)
For each objExchange_MessageTrackingEntry in listExchange_MessageTrackingEntries
for i = 0 to objExchange_MessageTrackingEntry.RecipientCount
objtempaddr =
search_user(objExchange_MessageTrackingEntry.RecipientAddress(i),1)
if len(objtempaddr) <> 0 then
if len(objdlladdress) <> 0 then
objdlladdress = objdlladdress & ";" & objtempaddr
else
objdlladdress = objtempaddr
end if
end if
objtempaddr = ""
next
Next
if len(objdlladdress) <> 0 then msgobj1.fields("urn:schemas:mailheader:to") =
objdlladdress
msgobj1.fields("http://schemas.microsoft.com/exchange/outlookmessageclass") =
"IPM.Note"
msgobj1.fields.update
msgobj1.datasource.save
set objWMIExchange = nothing
set listExchange_MessageTrackingEntries = nothing
end if
set msgobj1 = nothing
end if
end sub

function search_user(senaddr,searchtype)
Set objDNS = CreateObject("ADSystemInfo")
DomainName = LCase(objDNS.DomainDNSName)
Set oRoot = GetObject("LDAP://" & DomainName & "/rootDSE")
strDefaultNamingContext = oRoot.get("defaultNamingContext")
if instr(senaddr,"/CN=") then
strQuery = "select distinguishedName,mail,displayname,objectCategory from
'LDAP://" & strDefaultNamingContext & "' where legacyExchangeDN = '" & senaddr &
"'"
else
strQuery = "select distinguishedName,mail,displayname,objectCategory from
'LDAP://" & strDefaultNamingContext & "' where mail = '" & senaddr & "'"
end if

Set oConn = CreateObject("ADODB.Connection") 'Create an ADO Connection
oConn.Provider = "ADsDSOOBJECT" ' ADSI OLE-DB provider
oConn.Open "ADs Provider"

Set oComm = CreateObject("ADODB.Command") ' Create an ADO Command
oComm.ActiveConnection = oConn
oComm.Properties("Page Size") = 1000
oComm.CommandText = strQuery
Set rs = oComm.Execute
while not rs.eof
if searchtype = 1 then
if instr(lcase(rs.fields("objectCategory")),"cn=group,") or
instr(lcase(rs.fields("objectCategory")),"cn=ms-exch-dynamic-distribution-list,")
then
dispname = rs.fields("displayname")
emailad = rs.fields("mail")
search_user = chr(34) & dispname & chr(34) & "<" & emailad & ">"
end if
else
strsendingusername = "LDAP://" & rs.Fields("distinguishedName")
set objsenduser = getobject(strsendingusername)
inplinearray = Split(objsenduser.msExchHomeServerName, "=", -1, 1)
strservername = inplinearray(ubound(inplinearray))
search_user = strservername
end if
rs.movenext
wend


end function

</SCRIPT>
 

Thursday, January 06, 2005

Displaying the Store file usage Trends via Script using the Event log

Continuing on from some of my previous scripts last month around mail store file usage and backup results this script expands on this idea a little. As I’ve mentioned previously when the backup runs on an Exchange server (as long as it’s using the Exchange backup API eg Brightstore, Veritas etc). It logs to the event log a whole lot of useful information about when it started when it stopped and how much data (the size of each database file) that is going to be backed up. Because the event log is a historical record depending on how you have your eventlogs setup you will have a record that goes back of a number of weeks or months of how large the database store files where when each of the backups occurred. All this information is stored in the eventid 220.

So what this script does is like the others scripts before it is query AD for all the mail and public folder stores in your domain. Then query the exchange server’s event log for all the 220 events for a configured time period. I’ve set the period to 60 days in the script but you can increase or decrease this amount depending on your needs. Increasing the number of days will slow the script down because it will have more entries to filter though (the real limitation is going to be your actually event log size). The information about each day’s backup is stored in a multi dimensional array which stores the date of the event, the size of the data file and the usage between this backup and the last backup. Once the array has been fully populated with all the available events a report is then displayed to the command line showing the full usage for the number of days measured (just compares the lower array entry and the upper array entry). After this trend information is shown by looping though the array and showing the amount of usage in groups of 7 days as well as a daily average at the end. This allows you to see the amount of growth your experience each week and see where your spikes and troughs are.

Ive posted a downloaded copy of the code here

The script looks like

set conn = createobject("ADODB.Connection")
set com = createobject("ADODB.Command")
Set iAdRootDSE = GetObject("LDAP://RootDSE")
strNameingContext = iAdRootDSE.Get("configurationNamingContext")
rangeStep = 999
lowRange = 0
highRange = lowRange + rangeStep
Conn.Provider = "ADsDSOObject"
Conn.Open "ADs Provider"
mbQuery = ";(objectCategory=msExchPrivateMDB);name,distinguishedName;subtree"
pfQuery = ";(objectCategory=msExchPublicMDB);name,distinguishedName;subtree"
Com.ActiveConnection = Conn
Com.CommandText = mbQuery
Set Rs = Com.Execute
Wscript.echo "Mailbox Stores"
wscript.echo
While Not Rs.EOF
objmailstorename = "LDAP://" & Rs.Fields("distinguishedName")
set objmailstore = getObject(objmailstorename)
servername = mid(objmailstore.msExchOwningServer,4,instr(objmailstore.msExchOwningServer,",")-4)
wscript.echo Rs.Fields("name")
wscript.echo
getbackupdata = queryeventlog(servername,objmailstore.msExchEDBFile,objmailstore.msExchSLVFile)
Rs.MoveNext

Wend
Wscript.echo "Public Folder Stores"
Wscript.echo
Com.CommandText = pfQuery
Set Rs1 = Com.Execute
While Not Rs1.EOF
objmailstorename = "LDAP://" & Rs1.Fields("distinguishedName")
set objmailstore = getObject(objmailstorename)
servername = mid(objmailstore.msExchOwningServer,4,instr(objmailstore.msExchOwningServer,",")-4)
wscript.echo Rs1.Fields("name")
wscript.echo
getbackupdata = queryeventlog(servername,objmailstore.msExchEDBFile,objmailstore.msExchSLVFile)
Rs1.MoveNext

Wend
Rs.Close
Rs1.close
Conn.Close
Set Rs = Nothing
Set Rs1 = Nothing
Set Com = Nothing
Set Conn = Nothing


function queryeventlog(servername,edbfilename,stmfilename)
days = 60
SB = 0
edbarraycnt = 0
stmarraycnt = 0
dtmStartDate = CDate(Date) - days
dtmStartDate = Year(dtmStartDate) & Right( "00" & Month(dtmStartDate), 2) & Right( "00" & Day(dtmStartDate), 2)
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & servername & "\root\cimv2")
Set colLoggedEvents = objWMIService.ExecQuery("Select * from Win32_NTLogEvent Where Logfile='Application' and Eventcode = '220' and TimeWritten >= '" & dtmStartDate & "'",,48)
For Each objEvent in colLoggedEvents
SB = 1
Time_Written = objEvent.TimeWritten
Time_Written = left(Time_Written,(instr(Time_written,".")-1))
if instr(objEvent.Message,edbfilename) then
redim Preserve edbarray(3,edbarraycnt)
if edbarraycnt = 0 then
edbarray(0,edbarraycnt) = 0
edbarray(1,edbarraycnt) = dateserial(mid(Time_Written,1,4),mid(Time_Written,5,2),mid(Time_Written,7,2))
edbarray(2,edbarraycnt) = Mid(objEvent.Message,(InStr(objEvent.Message,"(size")+6),(InStr(objEvent.Message,"Mb)")-1)-(InStr(objEvent.Message,"(size")+6))
else
edbarray(0,(edbarraycnt-1)) = edbarray(2,(edbarraycnt-1)) - Mid(objEvent.Message,(InStr(objEvent.Message,"(size")+6),(InStr(objEvent.Message,"Mb)")-1)-(InStr(objEvent.Message,"(size")+6))
edbarray(1,edbarraycnt) = dateserial(mid(Time_Written,1,4),mid(Time_Written,5,2),mid(Time_Written,7,2))
edbarray(2,edbarraycnt) = Mid(objEvent.Message,(InStr(objEvent.Message,"(size")+6),(InStr(objEvent.Message,"Mb)")-1)-(InStr(objEvent.Message,"(size")+6))
edbarraysum = edbarray(0,(edbarraycnt-1)) + edbarraysum
end if
queryeventlog = dateserial(mid(Time_Written,1,4),mid(Time_Written,5,2),mid(Time_Written,7,2))
edbarraycnt = edbarraycnt + 1
else
if instr(objEvent.Message,stmfilename) then
redim Preserve stmarray(3,stmarraycnt)
if stmarraycnt = 0 then
stmarray(0,stmarraycnt) = 0
stmarray(1,stmarraycnt) = dateserial(mid(Time_Written,1,4),mid(Time_Written,5,2),mid(Time_Written,7,2))
stmarray(2,stmarraycnt) = Mid(objEvent.Message,(InStr(objEvent.Message,"(size")+6),(InStr(objEvent.Message,"Mb)")-1)-(InStr(objEvent.Message,"(size")+6))
else
stmarray(0,(stmarraycnt-1)) = stmarray(2,(stmarraycnt-1)) - Mid(objEvent.Message,(InStr(objEvent.Message,"(size")+6),(InStr(objEvent.Message,"Mb)")-1)-(InStr(objEvent.Message,"(size")+6))
stmarray(1,stmarraycnt) = dateserial(mid(Time_Written,1,4),mid(Time_Written,5,2),mid(Time_Written,7,2))
stmarray(2,stmarraycnt) = Mid(objEvent.Message,(InStr(objEvent.Message,"(size")+6),(InStr(objEvent.Message,"Mb)")-1)-(InStr(objEvent.Message,"(size")+6))
stmarraysum = stmarray(0,(stmarraycnt-1)) + stmarraysum
end if
stmarraycnt = stmarraycnt + 1
end if
end if
next
if SB = 0 then queryeventlog = "No Backup recorded in the last 7 Days"
if edbarraycnt > 1 then
Wscript.echo "EDB Mailstore file Size on " & edbarray(1,(edbarraycnt-1)) & " Size :" & edbarray(2,(edbarraycnt-1)) &" MB"
Wscript.echo "EDB Mailstore file Size on " & edbarray(1,0) & " Size :" & edbarray(2,0) &" MB"
Wscript.echo "EDB Mailstore file size Growth over " & datediff("d",edbarray(1,(edbarraycnt-1)),edbarray(1,0)) & " Days " & edbarray(2,0) - edbarray(2,(edbarraycnt-1)) & " MB"
wscript.echo
Wscript.echo "STM Mailstore file Size on " & stmarray(1,(stmarraycnt-1)) & " Size :" & stmarray(2,(stmarraycnt-1)) &" MB"
Wscript.echo "STM Mailstore file Size on " & stmarray(1,0) & " Size :" & stmarray(2,0) &" MB"
Wscript.echo "STM Mailstore File Size Growth over " & datediff("d",stmarray(1,(stmarraycnt-1)),stmarray(1,0)) & " Days " & stmarray(2,0) - stmarray(2,(stmarraycnt-1)) & " MB"
wscript.echo
Wscript.echo "Weekly Growth Trends EDB File"
wscript.echo
sdate = edbarray(1,0)
ssize = edbarray(2,0)
for i = 0 to (edbarraycnt-1)
if datediff("d",edbarray(1,i),sdate) > 6 then
wscript.echo "Growth on " & edbarray(1,i) & " to " & sdate & ": " & ssize-edbarray(2,i) & " MB"
sdate = edbarray(1,i)
ssize = edbarray(2,i)
end if
next
wscript.echo "Daily Average : " & formatnumber(edbarraysum/(datediff("d",edbarray(1,(edbarraycnt-1)),edbarray(1,0))),2) & " MB"
wscript.echo
Wscript.echo "Weekly Growth Trends STM File"
wscript.echo
sdate = stmarray(1,0)
ssize = stmarray(2,0)
for i = 0 to (stmarraycnt-1)
if datediff("d",stmarray(1,i),sdate) > 6 then
wscript.echo "Growth on " & stmarray(1,i) & " to " & sdate & ": " & ssize-stmarray(2,i) & " MB"
sdate = stmarray(1,i)
ssize = stmarray(2,i)
end if
next
wscript.echo "Daily Average : " & formatnumber(stmarraysum/(datediff("d",stmarray(1,(stmarraycnt-1)),stmarray(1,0))),2) & " MB"
wscript.echo
end if
end function

Tuesday, January 04, 2005

Copying email from the Inbox to eml files on the file system

Somebody asked how to copy email from a mailbox or public folder to the file system using WebDAV. One way of doing this is to grab the email as stream using a WebDAV get as illustrated in the Exchange SDK here
Once you have the email as a stream you can then use an ADO stream object's savetofile method to save it as an eml file. If you combine that with a webdav search you can then select all the emails in a certain folder and export this to a folder on the file system. The following example exports all the mail in a inbox to a folder on the c: drive called exp. I've posted a downloadable copy of this code here.

server = "servername"
mailbox = "mailbox"
set fso = createobject("Scripting.FileSystemObject")
strURL = "http://" & server & "/exchange/" & mailbox & "/inbox/"
strURL1 = "http://" & server & "/exchange/" & mailbox & "/sent items/"
strQuery = ""
strQuery = strQuery & "SELECT ""DAV:displayname"", ""urn:schemas:httpmail:subject"""
strQuery = strQuery & " FROM scope('shallow traversal of """
strQuery = strQuery & strURL & """') Where ""DAV:ishidden"" = False AND ""DAV:isfolder"" = False AND "
strQuery = strQuery & """DAV:contentclass"" = 'urn:content-classes:message'
"
set req = createobject("microsoft.xmlhttp")
req.open "SEARCH", strURL, false
req.setrequestheader "Content-Type", "text/xml"
rem req.setrequestheader "Range", "rows=0-100"
req.setRequestHeader "Translate","f"
req.send strQuery
If req.status >= 500 Then
ElseIf req.status = 207 Then
set oResponseDoc = req.responseXML
set oNodeList = oResponseDoc.getElementsByTagName("a:displayname")
set oNodeList1 = oResponseDoc.getElementsByTagName("a:href")
For i = 0 To (oNodeList.length -1)
set oNode = oNodeList.nextNode
set oNode1 = oNodeList1.nextNode
df = expmail(oNode.Text,oNode1.text)
Next
Else
End If

function expmail(displayname,href)
req.open "GET", href, false
req.setRequestHeader "Translate","f"
req.send
fname = replace(replace(replace(replace(replace(displayname,":","-"),"\",""),"/",""),"?",""),chr(34),"")
fname = replace(replace(replace(replace(replace(replace(fname,"<",""),">",""),chr(11),""),"*",""),"|",""),"(","")
fname = replace(replace(replace(fname,")",""),chr(12),""),chr(15),"")
fname = "c:\exp\" & fname
wscript.echo fname
set stm = createobject("ADODB.Stream")
stm.open
msgstring = req.responsetext
stm.type = 2
stm.Charset = "x-ansi"
stm.writetext msgstring,0
stm.Position = 0
stm.type = 1
stm.savetofile fname
set stm = nothing

end function