Skip to main content

Creating a RSS feed of all new items in all public folders over the past 24 hours

I’m having a bit of a RSS feed week this week here’s another interesting one. A while ago I created this RSS event sink for a public folder that would generate a feed whenever a new item was posted in a Public Folder. This is useful but over a large number of folders having a separate feed for every folder is a pain and usually it’s a matter of getting across the new information that’s been added to a possible large number of folders that’s important. So what I’ve come up with is a script that will scan though every folder in the public folder tree on a server and then create a feed that has a post for each new item in each public folder within the whole public folder tree (where theres are replica available). The one problem with this script is it doesn’t really respect permissions so if you have folders that have information in them that is supposed to be restricted you might want to include some if statements so these folders are skipped.


This script use WebDAV to query each public folder it’s loosely based like a few of my scripts lately on the code from the mailbox size KB . Each folder in the public folder tree is recursively queried for items that where created in the last 24 hours and a RSS file is then built using the XMLDom com object. That script use the Admin Virtual root which means it can run using Delegated Exchange Administration rights and won’t be hampered by public folder permission. An ADSI query is used to find out what the default SMTP domain is in the default recipient policy. By default the script isn’t using SSL which may mean you need to adjust the following line if you are using SSL on the ExAdmin Directory.


falias = "http://" & servername & "/exadmin/admin/" & dpDefaultpolicy & "/Public Folders/"

To customize the location where the RSS file is created modify the 2 line

feedfile = ""c:\temp\feedpubnew.xml"

The script itself takes one commandline parameter which is the servername of the server you want to run it against so to run this script you need something like

cscript pubrssnew.vbs servername

I’ve put a download copy of this script here the script itself looks like

Servername = wscript.arguments(0)
feedfile = "feedpubnew.xml"
set shell = createobject("wscript.shell")
strValueName = "HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias"
minTimeOffset = shell.regread(strValueName)
toffset = datediff("h",DateAdd("n", minTimeOffset, now()),now())
dtListFrom = DateAdd("n", minTimeOffset, now())
gmttime = dateadd("h",-toffset,now())
dateto = isodateit(gmttime)
datefrom = isodateit(DateAdd("d",-1,gmttime))
set objdom = CreateObject("MICROSOFT.XMLDOM")
set req = createobject("microsoft.xmlhttp")
rem Create Root RSS feed
Set objField = objDom.createElement("rss")
Set objattID = objDom.createAttribute("version")
objattID.Text = "2.0"
objField.setAttributeNode objattID
objDom.appendChild objField
Set objField1 = objDom.createElement("channel")
objfield.appendChild objField1
Set objField3 = objDom.createElement("link")
objfield3.text = "http://" & Servername & "/public"
objfield1.appendChild objField3
Set objField4 = objDom.createElement("title")
objfield4.text = "Public Folder Feed"
objfield1.appendChild objField4
Set objField5 = objDom.createElement("description")
objfield5.text = "New Public Folder items in the last 24 Hours"
objfield1.appendChild objField5
Set objField6 = objDom.createElement("language")
objfield6.text = "en-us"
objfield1.appendChild objField6
Set objField7 = objDom.createElement("lastBuildDate")
objfield7.text = WeekdayName(weekday(now),3) & ", " & day(now()) & " " &
Monthname(month(now()),3) & " " & year(now()) & " " & formatdatetime(now(),4) &
":00 GMT"
objfield1.appendChild objField7

set com = createobject("ADODB.Command")
set conn = createobject("ADODB.Connection")
Set iAdRootDSE = GetObject("LDAP://RootDSE")
strNameingContext = iAdRootDSE.Get("configurationNamingContext")
strDefaultNamingContext = iAdRootDSE.Get("defaultNamingContext")
Conn.Provider = "ADsDSOObject"
Conn.Open "ADs Provider"
polQuery = "<LDAP://" & strNameingContext &
">;(&(objectCategory=msExchRecipientPolicy)(cn=Default
Policy));distinguishedName,gatewayProxy;subtree"
svcQuery = "<LDAP://" & strNameingContext &
">;(&(objectCategory=msExchExchangeServer)(cn=" & Servername &
"));cn,name,legacyExchangeDN;subtree"
Com.ActiveConnection = Conn
Com.CommandText = polQuery
Set plRs = Com.Execute
while not plRs.eof
for each adrobj in plrs.fields("gatewayProxy").value
if instr(adrobj,"SMTP:") then dpDefaultpolicy =
right(adrobj,(len(adrobj)-instr(adrobj,"@")))
next
plrs.movenext
wend
wscript.echo dpDefaultpolicy
falias = "http://" & servername & "/exadmin/admin/" & dpDefaultpolicy & "/Public
Folders/"
RecurseFolder(falias)
wscript.echo falias
set conn = nothing
set com = nothing
set wfile = nothing
set fso = Nothing
Set objPI = objDom.createProcessingInstruction("xml", "version='1.0'")
objDom.insertBefore objPI, objDom.childNodes(0)
objdom.save("c:\temp\" & feedfile)

Public Sub RecurseFolder(sUrl)

req.open "SEARCH", sUrl, False, "", ""
sQuery = "<?xml version=""1.0""?>"
sQuery = sQuery & "<g:searchrequest xmlns:g=""DAV:"">"
sQuery = sQuery & "<g:sql>SELECT ""http://schemas.microsoft.com/"
sQuery = sQuery & "mapi/proptag/x0e080003"", ""DAV:hassubs"" FROM SCOPE "
sQuery = sQuery & "('SHALLOW TRAVERSAL OF """ & sUrl & """') "
sQuery = sQuery & "WHERE ""DAV:isfolder"" = true and ""DAV:ishidden"" = false
and ""http://schemas.microsoft.com/mapi/proptag/x36010003"" = 1"
sQuery = sQuery & "</g:sql>"
sQuery = sQuery & "</g:searchrequest>"
req.setRequestHeader "Content-Type", "text/xml"
req.setRequestHeader "Translate", "f"
req.setRequestHeader "Depth", "0"
req.setRequestHeader "Content-Length", "" & Len(sQuery)
req.send sQuery
Set oXMLDoc = req.responseXML
Set oXMLSizeNodes = oXMLDoc.getElementsByTagName("d:x0e080003")
Set oXMLHREFNodes = oXMLDoc.getElementsByTagName("a:href")
Set oXMLHasSubsNodes = oXMLDoc.getElementsByTagName("a:hassubs")
For i = 0 to oXMLSizeNodes.length - 1
call procfolder(oXMLHREFNodes.Item(i).nodeTypedValue,sUrl)
wscript.echo oXMLHREFNodes.Item(i).nodeTypedValue
If oXMLHasSubsNodes.Item(i).nodeTypedValue = True Then
call RecurseFolder(oXMLHREFNodes.Item(i).nodeTypedValue)
End If
Next
End Sub

sub procfolder(strURL,pfname)
wscript.echo strURL
ReDim resarray(1,6)
strQuery = "<?xml version=""1.0""?><D:searchrequest xmlns:D = ""DAV:""
xmlns:b=""urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"">"
strQuery = strQuery & "<D:sql>SELECT ""DAV:displayname"",
""urn:schemas:httpmail:subject"", "
strQuery = strQuery & """DAV:creationdate"", ""DAV:getcontentlength"", "
strQuery = strQuery & """urn:schemas:httpmail:fromemail"",
""urn:schemas:httpmail:to"""
strQuery = strQuery & " FROM scope('shallow traversal of """
strQuery = strQuery & strURL & """') Where ""DAV:ishidden"" = False AND
""DAV:isfolder"" = False AND "
'strQuery = strQuery & """urn:schemas:httpmail:datereceived"" &lt; CAST(""" &
dateto & """ as 'dateTime') AND "
strQuery = strQuery & """urn:schemas:httpmail:datereceived"" &gt; CAST(""" &
datefrom & """ as 'dateTime')</D:sql></D:searchrequest>"
req.open "SEARCH", strURL, false
req.setrequestheader "Content-Type", "text/xml"
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")
set oSize = oResponseDoc.getElementsByTagName("a:getcontentlength")
set odatereceived = oResponseDoc.getElementsByTagName("a:creationdate")
set fEmail = oResponseDoc.getElementsByTagName("d:fromemail")
set TEmail = oResponseDoc.getElementsByTagName("d:to")
For i = 0 To (oNodeList.length -1)
set oNode = oNodeList.nextNode
set oNode1 = oNodeList1.nextNode
set oNode2 = oSize.nextNode
set oNode3 = odatereceived.nextNode
set oNode4 = fEmail.nextNode
set oNode5 = TEmail.nextNode
wscript.echo oNode3.text
export = 0
If InStr(LCase(oNode4.text),LCase(domaintosearch))Then
export = 1
End If
if InStr(LCase(oNode5.text),LCase(domaintosearch))Then
export = 1
End If
If export = 1 Then
Call AddtoFeed(oNode1.text,oNode.text)
End if
Next
Else
End If

end sub

sub AddtoFeed(exporthref,subject)

xmlreqtxt = "<?xml version='1.0'?><a:propfind xmlns:a='DAV:'
xmlns:m='urn:schemas:httpmail:'
xmlns:mapi='http://schemas.microsoft.com/mapi/proptag/'>" _
&
"<a:prop><mapi:x6707001E/></a:prop><a:prop><a:displayname/></a:prop><a:prop><m:subject/></a:prop><a:prop><m:fromemail/>"_
&
"</a:prop><a:prop><m:htmldescription/></a:prop><a:prop><m:datereceived/></a:prop></a:propfind>"
req.open "PROPFIND", exporthref, false, "", ""
req.setRequestHeader "Content-Type", "text/xml; charset=""UTF-8"""
req.setRequestHeader "Depth", "0"
req.setRequestHeader "Translate", "f"
req.send xmlreqtxt
set oResponseDoc1 = req.responseXML
set pfParentFolder = oResponseDoc1.getElementsByTagName("d:x6707001E")
set feFromEmail = oResponseDoc1.getElementsByTagName("e:fromemail")
set sjSubject = oResponseDoc1.getElementsByTagName("e:subject")
set drDateRecieved = oResponseDoc1.getElementsByTagName("e:datereceived")
set bdHtmlBody = oResponseDoc1.getElementsByTagName("e:htmldescription")
set dnDisplayName = oResponseDoc1.getElementsByTagName("a:displayname")

For i = 0 To (sjSubject.length -1)
set pfnode = sjSubject.nextNode
set pfnode1 = feFromEmail.nextNode
set pfnode2 = drDateRecieved.nextNode
set pfnode3 = bdHtmlBody.nextNode
Set pfnode4 = pfParentFolder.nextNode
Set pfnode5 = dnDisplayName.nextNode
wscript.echo pfnode.text
wscript.echo pfnode1.text
wscript.echo pfnode2.text
rem wscript.echo pfnode3.text
wscript.echo pfnode4.text
wscript.echo pfnode5.text
wscript.echo left(Replace(pfnode2.text,"T"," "),19)
Set objField2 = objDom.createElement("item")
objfield1.appendChild objField2
Set objField8 = objDom.createElement("guid")
Set objattID8 = objDom.createAttribute("isPermaLink")
objattID8.Text = "false"
objField8.setAttributeNode objattID8
objfield8.text = exporthref
objfield2.appendChild objField8
Set objField9 = objDom.createElement("title")
objfield9.text = pfnode.text
if objfield9.text = "" then objfield9.text = "Blank"
objfield2.appendChild objField9
Set objField10 = objDom.createElement("link")
objfield10.text = "http://" & Servername & "/public" & pfnode4.text
objfield2.appendChild objField10
Set objField11 = objDom.createElement("description")
objfield11.text = pfnode3.text
if objfield11.text = "" then objfield11.text = "Blank"
objfield2.appendChild objField11
Set objField12 = objDom.createElement("author")
objfield12.text = pfnode1.text
objfield2.appendChild objField12
Set objField13 = objDom.createElement("pubDate")
objfield13.text = WeekdayName(weekday(left(Replace(pfnode2.text,"T"," "),19)),3)
& ", " & day(left(Replace(pfnode2.text,"T"," "),19)) & " " &
Monthname(month(left(Replace(pfnode2.text,"T"," "),19)),3) & " " &
year(left(Replace(pfnode2.text,"T"," "),19)) & " " &
formatdatetime(left(Replace(pfnode2.text,"T"," "),19),4) & ":00 GMT"
objfield2.appendChild objField13
Set objField14 = objDom.createElement("category")
objfield14.text = unescape(Replace(LCase(pfnode4.text),LCase(pfnode5.text),""))
objfield2.appendChild objField14
set objfield2 = nothing
set objfield8 = nothing
set objfield9 = nothing
set objfield10 = nothing
set objfield11 = nothing
set objfield12 = nothing
set objfield13 = nothing
next

End Sub


function isodateit(datetocon)
strDateTime = year(datetocon) & "-"
if (Month(datetocon) < 10) then strDateTime = strDateTime & "0"
strDateTime = strDateTime & Month(datetocon) & "-"
if (Day(datetocon) < 10) then strDateTime = strDateTime & "0"
strDateTime = strDateTime & Day(datetocon) & "T" & formatdatetime(datetocon,4)
&":00Z"
isodateit = strDateTime
end function

Popular posts from this blog

Testing and Sending email via SMTP using Opportunistic TLS and oAuth in Office365 with PowerShell

As well as EWS and Remote PowerShell (RPS) other mail protocols POP3, IMAP and SMTP have had OAuth authentication enabled in Exchange Online (Official announcement here ). A while ago I created  this script that used Opportunistic TLS to perform a Telnet style test against a SMTP server using SMTP AUTH. Now that oAuth authentication has been enabled in office365 I've updated this script to be able to use oAuth instead of SMTP Auth to test against Office365. I've also included a function to actually send a Message. Token Acquisition  To Send a Mail using oAuth you first need to get an Access token from Azure AD there are plenty of ways of doing this in PowerShell. You could use a library like MSAL or ADAL (just google your favoured method) or use a library less approach which I've included with this script . Whatever way you do this you need to make sure that your application registration  https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th

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 Graph is limited to a m
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.