Skip to main content

Finding what Resources are being used from a Meeting Request

I've blogged about resources in meetings before but this question came up last week about how do you tell which resources have been booked from a calendar request message(meeting invitation). When someone creates a meeting the resources that are booked (or attempting to be booked) with the meeting get stored in the BCC field of the appointment object. In the calendar request messages (invitations) that go out to the users (and resource mailboxes if your using some sort of auto accept system) the resources aren't included in the calendar request message (not even in the recipients collection even when the resource mailbox is receiving the calendar request). If you use Outlook to do the booking it does copy the resources display name into the location property but with OWA the location field is left blank unless the user specifically enters something . So from a calendar request message you received from a meeting organized by OWA how could you tell which resources where being booked with that meeting.

Here are a couple of methods that may help

The Mapi property 0x8167001E lists all the displaynames of attendees of a meeting and this seems to include all the resources as well. So what you can do is grab this property do a split on it to get the entries into an array. Loop though the array and check if each address is in the To or CC field of the appointment and if its not then its a resource. eg

Set iCalMsg = CreateObject("CDO.Message")
iCalMsg.datasource.open "itemurl"
recplist =
iCalMsg.fields("http://schemas.microsoft.com/mapi/proptag/0x8167001E")
recparray = split(recplist,";",-1,1)
for i = lbound(recparray) to ubound(recparray)
if instr(iCalMsg.fields("http://schemas.microsoft.com/mapi/proptag/0x0E04001E"),recparray(I)) then
else
if instr(iCalMsg.fields("http://schemas.microsoft.com/mapi/proptag/0x0E03001E"),recparray(I)) then
else
wscript.echo recparray(I)
end if
end if
next

Another method you can use is if you loop though the attendees collection of the appointment associated with the calendar request you can find the organizer of the appointment. Once you know the organizer of the appointment you can then use this along with the urn:schemas:calendar:uid field which uniquely identifies each appointment to call the GetAssociatedItem method of the calendar item. This will (if you have the rights to) connect to the organizers mailbox and then retrieve the master appointment object which will contain resources in the attendees collection . This all uses CDOEX and CDOEXM and the file URL scheme so for this to work the resource mailbox and organizers mailbox has have be on the same server.

Set iCalMsg = CreateObject("CDO.CalendarMessage")
iCalMsg.datasource.open "itemurl"
For Each iCalPart In iCalMsg.CalendarParts
Set iAppt = iCalPart.GetUpdatedItem
cuid1 = iAppt.fields("urn:schemas:calendar:uid")
for each attend in iAppt.Attendees
if attend.IsOrganizer <> 0 then
Set Person = CreateObject("CDO.Person")
strURL = attend.address
Person.DataSource.Open strURL
Set Mailbox = Person.GetInterface("IMailbox")
set iAppt1 = iCalPart.GetAssociatedItem(Mailbox.calendar)
for each attend1 in iAppt1.Attendees
 wscript.echo attend1.address
 wscript.echo attend1.role
 wscript.echo attend1.status
 wscript.echo attend1.type
next
end if
next
Next

If you wanted to use the second method but the mailboxes are on separate servers then something similar can be done using three webDAV queries and some ADSI. The following example first grabs the calendar message using a WebDAV GET and parses the organizer of the meeting out of the vCalendar body part and also the calendar UID. An ADSI query is then performed using the SMTP address of the organizer to retrieve the msExchHomeServerName property which tells you which server the mailbox is on. A second WebDAV search is then done of the organizers calendar based on the Calender UID of the appointment. This should then locate the original appointment which is then retrieved using a WebDAV GET. The resource mailbox (or mailbox's) SMTP address's are then parsed out of the vCalendar body part.
I've posted a copy of all the scripts from this post here

set Req = createobject("Microsoft.XMLHTTP")
Req.open "GET","http://server/exchange/mailbox/inbox/calandermessage.EML",false
Req.setRequestHeader "Translate","f"
Req.send
attendeearry = split(req.responsetext,"ORGANIZER;",-1,1)
for i = 1 to ubound(attendeearry)
string1 = vbcrlf & " "
stparse = replace(attendeearry(i),string1,"")
attaddress = mid(stparse,(instr(stparse,"MAILTO:")+7),instr(stparse,chr(13)))
attaddress = mid(attaddress,1,(instr(attaddress,vbcrlf)-1))
next
uidarry = mid(req.responsetext,instr(req.responsetext,"UID:")+3,len(req.responsetext))
string1 = vbcrlf & " "
stparse = replace(uidarry,string1,"")
uidprop = mid(stparse,2,instr(stparse,vbcrlf))
uidprop = replace(uidprop,vbcrlf,"")
CUserID = replace(attaddress," ","")
Set objDNS = CreateObject("ADSystemInfo")
DomainName = LCase(objDNS.DomainDNSName)
Set oRoot = GetObject("LDAP://" & DomainName & "/rootDSE")
strDefaultNamingContext = oRoot.get("defaultNamingContext")
GALQueryFilter = "(&(&(&(& (mailnickname=*) (|
(&(objectCategory=person)(objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*)))
)))(objectCategory=user)(mail=" & CUserID & ")))"
strQuery = "<LDAP://" & DomainName & "/" & strDefaultNamingContext & ">;" &
GALQueryFilter &
";distinguishedName,msExchHomeServerName,msExchHideFromAddressLists;subtree"
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

server =
right(rs.fields("msExchHomeServerName"),len(rs.fields("msExchHomeServerName"))-(instr(rs.fields("msExchHomeServerName"),"cn=Servers/cn=")+13))
mailbox = attaddress
strURL = "http://" & server & "/exchange/" & mailbox & "/calendar/"
strQuery = "<?xml version=""1.0""?><D:searchrequest xmlns:D = ""DAV:"" >"
strQuery = strQuery & "<D:sql>SELECT ""DAV:href"" FROM scope('shallow traversal
of """
strQuery = strQuery & strURL & """') Where ""urn:schemas:calendar:uid"" = '" &
uidprop & "'</D:sql></D:searchrequest>"
set req = createobject("microsoft.xmlhttp")
req.open "SEARCH", strURL, false
req.setrequestheader "Content-Type", "text/xml"
req.setRequestHeader "Translate","f"
req.send strQuery
If req.status >= 500 Then
wscript.echo "Status: " & req.status
wscript.echo "Status text: An error occurred on the server."
ElseIf req.status = 207 Then
set oResponseDoc = req.responseXML
set oNodeList = oResponseDoc.getElementsByTagName("a:href")
For i = 0 To (oNodeList.length -2)
set oNode = oNodeList.nextNode
proccalmess(oNode.Text)
Next
Else
wscript.echo "Status: " & req.status
wscript.echo "Status text: " & req.statustext
wscript.echo "Response text: " & req.responsetext
End If

sub proccalmess(objhref)

Req.open "GET", objhref, false
Req.setRequestHeader "Translate","f"
Req.send
attendeearry = split(req.responsetext,"ATTENDEE;",-1,1)
for i = 1 to ubound(attendeearry)
string1 = vbcrlf & " "
stparse = replace(attendeearry(i),string1,"")
attaddress = mid(stparse,(instr(stparse,"MAILTO:")+7),instr(stparse,chr(13)))
attaddress = mid(attaddress,1,instr(attaddress,vbcrlf))
if instr(stparse,"=RESOURCE") then
wscript.echo attaddress
end if
next

end sub

Popular posts from this blog

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Gr...

Exporting and Uploading Mailbox Items using Exchange Web Services using the new ExportItems and UploadItems operations in Exchange 2010 SP1

Two new EWS Operations ExportItems and UploadItems where introduced in Exchange 2010 SP1 that allowed you to do a number of useful things that where previously not possible using Exchange Web Services. Any object that Exchange stores is basically a collection of properties for example a message object is a collection of Message properties, Recipient properties and Attachment properties with a few meta properties that describe the underlying storage thrown in. Normally when using EWS you can access these properties in a number of a ways eg one example is using the strongly type objects such as emailmessage that presents the underlying properties in an intuitive way that's easy to use. Another way is using Extended Properties to access the underlying properties directly. However previously in EWS there was no method to access every property of a message hence there is no way to export or import an item and maintain full fidelity of every property on that item (you could export the...

Sending a Message in Exchange Online via REST from an Arduino MKR1000

This is part 2 of my MKR1000 article, in this previous post  I looked at sending a Message via EWS using Basic Authentication.  In this Post I'll look at using the new Outlook REST API  which requires using OAuth authentication to get an Access Token. The prerequisites for this sketch are the same as in the other post with the addition of the ArduinoJson library  https://github.com/bblanchon/ArduinoJson  which is used to parse the Authentication Results to extract the Access Token. Also the SSL certificates for the login.windows.net  and outlook.office365.com need to be uploaded to the devices using the wifi101 Firmware updater. To use Token Authentication you need to register an Application in Azure https://msdn.microsoft.com/en-us/office/office365/howto/add-common-consent-manually  with the Mail.Send permission. The application should be a Native Client app that use the Out of Band Callback urn:ietf:wg:oauth:2.0:oob. You ...
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.