<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sidefumbling &#187; OCS 2007 R2</title>
	<atom:link href="http://www.flobee.net/category/office-communications-server/ocs-2007-r2/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.flobee.net</link>
	<description>The consequence of not having six hydrocoptic marzelvanes.</description>
	<lastBuildDate>Fri, 20 Jan 2012 17:04:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Update to OCS archiving script</title>
		<link>http://www.flobee.net/update-to-ocs-archiving-script/</link>
		<comments>http://www.flobee.net/update-to-ocs-archiving-script/#comments</comments>
		<pubDate>Mon, 01 Mar 2010 18:29:51 +0000</pubDate>
		<dc:creator>Scott</dc:creator>
				<category><![CDATA[OCS 2007]]></category>
		<category><![CDATA[OCS 2007 R2]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.flobee.net/?p=471</guid>
		<description><![CDATA[There are a couple of changes that have been made to improve the script. First, after running a report for a user with thousands of messages and not having any idea of the progress while it was running, I added progress windows during the two phases (content conversion and HTML report creation). The progress window [...]]]></description>
			<content:encoded><![CDATA[<p>There are a couple of changes that have been made to improve the script.</p>
<p>First, after running a report for a user with thousands of messages and not having any idea of the progress while it was running, I added progress windows during the two phases (content conversion and HTML report creation).  The progress window will tell you how many messages will be processed and how far along it is in that process.</p>
<p>Second, I discovered that hyperlinks in messages were not showing up in the report.  Looking at the HTML (or XML) source, I could see the link was there, but the way it was formatted in the XML file (using element enclosures) meant the conversion to HTML was confusing the parser.  Now I remove those characters prior to the link being written to the XML file.</p>
<p>I also optimized the message body conversion loop to remove redundant or obsolete code that was in the original script.  There are also some minor cosmetic changes here and there.</p>
<p>Lastly, I realized last week that the script only reports on peer-to-peer (P2P) conversations, not multiparty.  I spent some time trying to get multiparty conversations out of the database, but it is proving much more difficult than I anticipated.  The format of multiparty IMs in the archiving database is very different than P2P conversations.  I am still working on it, but I am not sure I will be able to make it work.  In the meantime, I added a note in the report that states it is only for P2P conversations.</p>
<p>The original zip file with the script has been updated, but you can download it here:<br />
Note: There is a file embedded within this post, please visit this post to download the file.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.flobee.net/update-to-ocs-archiving-script/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>OCS Archiving Reporter: Group by conversation, filter dates</title>
		<link>http://www.flobee.net/ocs-archiving-reporter-group-by-conversation-filter-dates/</link>
		<comments>http://www.flobee.net/ocs-archiving-reporter-group-by-conversation-filter-dates/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 00:46:21 +0000</pubDate>
		<dc:creator>Scott</dc:creator>
				<category><![CDATA[OCS 2007]]></category>
		<category><![CDATA[OCS 2007 R2]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[inline code]]></category>

		<guid isPermaLink="false">http://www.flobee.net/?p=433</guid>
		<description><![CDATA[Edit: The inline code is not the latest version of the script. To get the latest version, download the full script on the Downloads page (or via the link at the end of the post). The foundation for my script is from the OCS team at Microsoft, who created the original version. The script from [...]]]></description>
			<content:encoded><![CDATA[<p><font color="red">Edit:</font>  The inline code is not the latest version of the script.  To get the latest version, download the full script on the <a href="http://www.flobee.net/downloads">Downloads</a> page (or via the link at the end of the post).</p>
<p>The foundation for my script is from the OCS team at Microsoft, who created the <a href="http://communicationsserverteam.com/archive/2009/09/28/584.aspx">original version</a>.</p>
<p>The script from Microsoft grabs all the messages and outputs them all in one big table.  I wanted it to be displayed more logically, grouping an entire conversation (session) together so it is easier to follow the context of the messages.  This proved to be more daunting than I had anticipated.</p>
<p>All messages that occur in the same session have the same value for the SessionIdTime.  With that I can group those messages together.  But I needed a way to know when a new conversation started and ended. To get that I used the RANK function in SQL so that any rank of 1 indicates a new conversation.  The resulting SQL query for a single user is the following (the ticks at the end of the lines are for PowerShell):</p>
<pre class="brush:sql;gutter:false">
SELECT RANK() OVER(PARTITION BY SessionIdTime ORDER BY SessionIdTime, MessageIdTime) AS 'Rank', `
	SessionIdTime, MessageIdTime, Body, ContentTypeId, [from], [to] `
FROM `
(SELECT SessionIdTime, MessageIdTime, Body, ContentTypeId, u1.UserUri AS [from], u2.UserUri AS [to] FROM Messages, `
	Users u1, Users u2 WHERE Messages.FromId = u1.UserId AND Messages.ToId = u2.UserId AND u1.UserUri = '$User1' `
	AND LcsLog.dbo.Messages.Toast IS NULL `
UNION ALL `
SELECT SessionIdTime, MessageIdTime, Body, ContentTypeId, u2.UserUri AS [from], u1.UserUri AS [to] FROM Messages, `
	Users u2, Users u1 WHERE Messages.FromId = u2.UserId AND Messages.ToId = u1.UserId AND u1.UserUri = '$User1' `
	AND LcsLog.dbo.Messages.Toast IS NULL `
)AS dConversation
</pre>
<p>Now that I had the data, I needed to be able to use the XSLT to conditionally close a table the next time a rank of 1 is in the loop.  I had the hardest time trying to make the xsl:if and xsl:choose statements work.  Trying to include a <span class="flobeecode" id="codekeyword">&lt;/table&gt;</span> tag without the loop seeing the opening tag only caused errors.  If I used HTML notation, <span class="flobeecode" id="codekeyword">&amp;lt;/table&amp;gt;</span>, those characters were rendered as their literal ASCII representations rather than being parsed as HTML tags.</p>
<p>After trying for many, many hours, I decided to give up relying on the XML parser to convert the file to HTML and just do that parsing in the PowerShell script.  This has the benefit of not requiring external files to run the script (the XSLT and msxsl.exe).  The code below takes the XML output from the first part of the script and loops through each node (message).  If the rank is 1, it closes the previous table, opens a new one, and writes the message to a row.  If the rank is not 1, it means that a conversation has already been started and the message can simply being written in a new row.</p>
<pre class="brush:ps">
#Convert XML to HTML
$sourceXML = [xml](Get-Content $LocalPath)
Remove-Item -path IM.html -ea SilentlyContinue
pwd | % {[string]$LocalPath = $_.path}
$LocalPath = $LocalPath + "\IM.html"
Add-Content -path $LocalPath -Value '&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'
Add-Content -Path $LocalPath -Value '  "http://www.w3.org/TR/html4/loose.dtd"&gt;'
Add-Content -Path $LocalPath -Value "&lt;html&gt;"
Add-Content -Path $LocalPath -Value "&lt;head&gt;"
Add-Content -Path $LocalPath -Value "&lt;title&gt;IM Conversation Archive&lt;/title&gt;"
Add-Content -Path $LocalPath -Value "&lt;/head&gt;"
Add-Content -Path $LocalPath -Value "&lt;body&gt;"

Add-Content -Path $LocalPath -Value '&lt;font size="2" face="Verdana"&gt;'
Add-Content -Path $LocalPath -Value "&lt;h2 align=`"center`"&gt;$($sourceXML.IMConversation.Title)&lt;/h2&gt;"
Add-Content -Path $LocalPath -Value "&lt;h3 align=`"center`"&gt;$($sourceXML.IMConversation.Subtitle)&lt;/h2&gt;"
Add-Content -Path $LocalPath -Value "&lt;/font&gt;"
Add-Content -Path $LocalPath -Value '&lt;table border="0" cellpadding="1" width="100%" style="FONT-SIZE:8pt;FONT-FAMILY:verdana"&gt;'
foreach($IM in $sourceXML.IMConversation.IM)
	{
	if ($IM.Rank -eq "1")
		{
		Add-Content -Path $LocalPath -Value "&lt;/tbody&gt;&lt;/table&gt;&lt;br&gt;"
		Add-Content -Path $LocalPath -Value '&lt;table border="1" cellpadding="1" width="100%" style="FONT-SIZE:8pt;FONT-FAMILY:verdana">'
		Add-Content -Path $LocalPath -Value '&lt;thead>&lt;tr bgcolor="#C0C0C0" align="center"&gt;'
		Add-Content -Path $LocalPath -Value	'&lt;th&gt;&lt;font color="#0000FF"&gt;Session Time (UTC):&lt;/font&gt;&lt;/th&gt;'
		Add-Content -Path $LocalPath -Value	'&lt;th&gt;&lt;font color="#0000FF"&gt;Message Time (UTC):&lt;/font&gt;&lt;/th&gt;'
		Add-Content -Path $LocalPath -Value	'&lt;th&gt;&lt;font color="#0000FF"&gt;From:&lt;/font&gt;&lt;/th&gt;'
		Add-Content -Path $LocalPath -Value	'&lt;th&gt;&lt;font color="#0000FF"&gt;To:&lt;/font&gt;&lt;/th&gt;'
		Add-Content -Path $LocalPath -Value '&lt;th width="40%"&gt;&lt;font color="#0000FF"&gt;Message:&lt;/font&gt;&lt;/th&gt;'
		Add-Content -Path $LocalPath -Value	"&lt;/tr&gt;&lt;/thead&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;tbody&gt;&lt;tr&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td rowspan=`"100`" valign=`"top`"&gt;$($IM.SessionTime)&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.DateTime)&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.From)&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.To)&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.Body.get_FirstChild().get_Data())&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;/tr&gt;"
		}
	else
		{
		Add-Content -Path $LocalPath -Value	"&lt;tr&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.DateTime)&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.From)&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.To)&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;td&gt;$($IM.Body.get_FirstChild().get_Data())&lt;/td&gt;"
		Add-Content -Path $LocalPath -Value	"&lt;/tr&gt;"
		}
	}

Add-Content -Path $LocalPath -Value "&lt;/table>"
Add-Content -Path $LocalPath -Value "&lt;/body>"
Add-Content -Path $LocalPath -Value "&lt;/html>"
</pre>
<p>Lastly, I wanted to be able to filter on a date range within the archiving database.  So I added two arguments to the script after the users: <span class="flobeecode" id="codekeyword">-start</span> and <span class="flobeecode" id="codekeyword">-end</span>, both which are independently optional.  If you don&#8217;t specify a second user or you only specify an end date with one or two users, you need to use the parameter names in the command.  Otherwise, they are positional.  The date format to use is <span class="flobeecode" id="codestring">&quot;YYYY-MM-DD&quot;</span>.  To account for the presence of the date filter, this code is added to the script:</p>
<pre class="brush:ps">
If ($start -ne '')
	{
	#Start date has been specified
	$startdate = $start
	$start = "and Messages.MessageIdTime &gt;= '$start' "
	}
Else
	{
	$startdate = "Oldest record in the database"
	}

If ($end -ne '')
	{
	#End date has been specified
	$enddate = $end
	$end = "and Messages.MessageIdTime &lt;= '$end' "
	}
Else
	{
	$enddate = "Newest record in the database"
	}
</pre>
<p>The code is able to correctly parse the presence of a start date, end date, or both.  Now the following can be added to the end of the code block in the SQL query that makes up the derived table (the part in the nested parentheses):  <span class="flobeecode" id="codekeyword">+</span> <span class="flobeecode" id="codevariable">$start</span> <span class="flobeecode" id="codekeyword">+</span> <span class="flobeecode" id="codevariable">$end</span> <span class="flobeecode" id="codekeyword">+</span>.</p>
<p>Finally, the output is a pretty page with the subtitle that indicates the date range used, the table headers are formatted to visually separate each conversation, and each table is an indicated of a single conversation, regardless of the number of messages shown.</p>
<p>I don&#8217;t expect you to copy and paste all the code above into the script and have it magically work (especially since I made other minor changes to account for the subtitle, additional arguments, etc.), so you can download the entire script below or on the <a href="http://www.flobee.net/downloads">Downloads</a> page.Note: There is a file embedded within this post, please visit this post to download the file.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.flobee.net/ocs-archiving-reporter-group-by-conversation-filter-dates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

