<?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>VMTN Archives - LucD notes</title>
	<atom:link href="https://www.lucd.info/tag/vmtn/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.lucd.info/tag/vmtn/</link>
	<description>My PowerShell ramblings</description>
	<lastBuildDate>Wed, 08 Apr 2020 11:29:54 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>https://www.lucd.info/wp-content/uploads/2018/12/cropped-120px-Tibetan_Dharmacakra-32x32.png</url>
	<title>VMTN Archives - LucD notes</title>
	<link>https://www.lucd.info/tag/vmtn/</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/><atom:link rel="hub" href="https://websubhub.com/hub"/>	<item>
		<title>Search VMTN with REST API</title>
		<link>https://www.lucd.info/2017/12/31/search-vmtn-rest-api/</link>
					<comments>https://www.lucd.info/2017/12/31/search-vmtn-rest-api/#comments</comments>
		
		<dc:creator><![CDATA[LucD]]></dc:creator>
		<pubDate>Sun, 31 Dec 2017 18:53:19 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[VMTN]]></category>
		<guid isPermaLink="false">http://www.lucd.info/?p=5723</guid>

					<description><![CDATA[REST API are (nearly) everywhere! VMware&#8217;s VMTN website is no exception. I already [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Representational_state_transfer" target="_blank" rel="noopener noreferrer">REST API</a> are (nearly) everywhere! VMware&#8217;s <a href="https://communities.vmware.com/welcome" target="_blank" rel="noopener noreferrer">VMTN</a> website is no exception. I already did a post on <a href="https://www.lucd.info/2012/02/29/automate-your-vmtn-search/" target="_blank" rel="noopener noreferrer">Automate Your VMTN Search</a>, but that was entirely based on constructing URI and interpreting the returned webpages. For the occasion of the <a href="http://www.topitvideos.com/vmworld-2017-ser1875bu-the-power-hour-vmware-vsphere-powercli-10th-birthday-edition-vmware-vmworld/" target="_blank" rel="noopener noreferrer">PowerCLI&#8217;s 10th Birthday session</a> at VMworld, I wanted to produce some <strong>InfoGraphs</strong> on the <a href="https://communities.vmware.com/community/vmtn/automationtools/powercli" target="_blank" rel="noopener noreferrer">PowerCLI Community</a>. For those <strong>InfoGraphs</strong> I needed to harvest data from said VMTN Community, and I looked for a better way to do this. That is where the <a href="https://community.jivesoftware.com/docs/DOC-112244" target="_blank" rel="noopener noreferrer">REST API</a> offered by the <a href="https://www.jivesoftware.com/" target="_blank" rel="noopener noreferrer">Jive software,</a> om which the VMTN website is hosted, came in handy.</p>
<p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-5731" src="https://www.lucd.info/wp-content/uploads/2017/12/vmtn-search-jive.png" alt="" width="476" height="314" srcset="https://www.lucd.info/wp-content/uploads/2017/12/vmtn-search-jive.png 476w, https://www.lucd.info/wp-content/uploads/2017/12/vmtn-search-jive-300x198.png 300w" sizes="(max-width: 476px) 100vw, 476px" /></p>
<p>The functions I ended up with, are also a good example of how easy it is to consume REST API through PowerShell. And they also show how the basic techniques to work with REST API can be reused. Check out my <a href="https://github.com/lucdekens/VMTNRest" target="_blank" rel="noopener noreferrer">VMTNRest</a> repo.</p>
<p><span id="more-5723"></span></p>
<h2>VMTN and Jive</h2>
<p>The VMTN website is currently build on the <a href="https://blogs.vmware.com/vmtn/2017/03/vmtn-jive-8.html" target="_blank" rel="noopener noreferrer">Jive 8</a>, and besides the difference in some names, the major components of a Jive 8 hosted platform can be found back. These components are quite simple, but one needs to understand what is where, to be able to work with the REST API.</p>
<p>On a side note: working with REST API is quite straight-forward, the difficult part consists of understanding the setup and the logic of the platform behind the REST API. And the Jive platform is no exception.</p>
<p>There are four major <strong>endpoint services</strong> in a Jive environment. Since, for now, we only want to <strong>query</strong> the VMTN Communities, we will primarily be calling the REST API against the <strong>Content</strong> and <strong>People </strong>service endpoints. This will allow us to work with all the threads and documents published in the VMTN communities. And it will also allow us to gather information about users and groups in the VMTN communities.</p>
<p><img decoding="async" class="alignnone wp-image-5736 size-medium" src="https://www.lucd.info/wp-content/uploads/2017/12/endpoints-298x300.png" alt="" width="298" height="300" srcset="https://www.lucd.info/wp-content/uploads/2017/12/endpoints-298x300.png 298w, https://www.lucd.info/wp-content/uploads/2017/12/endpoints-150x150.png 150w, https://www.lucd.info/wp-content/uploads/2017/12/endpoints-170x170.png 170w, https://www.lucd.info/wp-content/uploads/2017/12/endpoints.png 627w" sizes="(max-width: 298px) 100vw, 298px" /></p>
<p>For a complete overview of the Jive REST API see the <a class="jive-link-external-small" href="https://developers.jivesoftware.com/api/v3/cloud/rest/index.html" target="_blank" rel="nofollow noopener noreferrer">Jive v3 REST API Reference Documentation</a>.</p>
<h2>Jive REST API calls</h2>
<p>Basically the Jive REST API calls are similar to most of the other REST API calls. You compose the URI, eventually with a number of optional keywords and specify the method to be used. The data is returned in JSON format.</p>
<p>But the like I mentioned before, there are a couple of Jive specific elements one needs to be aware off.</p>
<p>Let&#8217;s look at an example. The following is a typical thread as can be found in any of the VMTN communities. The numbers in these pictures refer to the Annotations further on in the post.</p>
<p><img decoding="async" class="alignnone wp-image-5749 size-large" src="https://www.lucd.info/wp-content/uploads/2017/12/thread2-1024x294.png" alt="" width="770" height="221" srcset="https://www.lucd.info/wp-content/uploads/2017/12/thread2-1024x294.png 1024w, https://www.lucd.info/wp-content/uploads/2017/12/thread2-300x86.png 300w, https://www.lucd.info/wp-content/uploads/2017/12/thread2-768x221.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/thread2-720x207.png 720w, https://www.lucd.info/wp-content/uploads/2017/12/thread2.png 1065w" sizes="(max-width: 770px) 100vw, 770px" /></p>
<p>The content of the thread is again nothing out of the extra ordinary.</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5750 size-large" src="https://www.lucd.info/wp-content/uploads/2017/12/thread3-1014x1024.png" alt="" width="770" height="778" srcset="https://www.lucd.info/wp-content/uploads/2017/12/thread3-1014x1024.png 1014w, https://www.lucd.info/wp-content/uploads/2017/12/thread3-297x300.png 297w, https://www.lucd.info/wp-content/uploads/2017/12/thread3-768x776.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/thread3-720x727.png 720w" sizes="auto, (max-width: 770px) 100vw, 770px" /></p>
<p>&nbsp;</p>
<p>If we &#8220;Get&#8221; that same thread through the REST API, there are a number of things to take note of.</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5756" src="https://www.lucd.info/wp-content/uploads/2017/12/thread1-1.png" alt="" width="2055" height="5073" srcset="https://www.lucd.info/wp-content/uploads/2017/12/thread1-1.png 2055w, https://www.lucd.info/wp-content/uploads/2017/12/thread1-1-122x300.png 122w, https://www.lucd.info/wp-content/uploads/2017/12/thread1-1-768x1896.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/thread1-1-415x1024.png 415w, https://www.lucd.info/wp-content/uploads/2017/12/thread1-1-720x1777.png 720w" sizes="auto, (max-width: 2055px) 100vw, 2055px" /></p>
<p>By the way, this last picture is the output of the REST API call made through the <a href="https://restlet.com/modules/client/" target="_blank" rel="noopener noreferrer">Chrome RestLet Client</a>, but could have been done through any other REST client, like for example <a href="https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en" target="_blank" rel="noopener noreferrer">PostMan</a>.</p>
<h3>Annotation</h3>
<ol>
<li>Like any other REST API call, each call is composed of three components
<ol style="list-style-type: upper-alpha;">
<li>The VMTN Jive community <strong>location</strong>, i.e. https://communities.vmware.com</li>
<li>The Jive REST API <strong>prefix</strong>, i.e. /api/core/v3</li>
<li>The REST <strong>endpoint</strong>, i.e. contents</li>
<li>Optional <strong>fields</strong>. In this example we ask the endpoint to return just one result at a time, and to only return entries of type &#8216;discussion&#8217;</li>
</ol>
</li>
<li>The Jive REST API accepts three <a href="https://developers.jivesoftware.com/api/v3/cloud/rest/index.html#authentication" target="_blank" rel="noopener noreferrer">types of authentication</a>. In our example we used <strong>Basic Authentication</strong>. The authentication string is passed as a Header in the REST API call. We also specify that all data shall be in the JSON format. <strong><span style="background-color: yellow;">Update</span></strong>: it looks as if <strong>Basic Authentication</strong> to call the REST API is not supported in the current Jive version for &#8220;federated&#8221; user accounts. I&#8217;m still looking into that.</li>
<li>The &#8220;throw&#8221; line is is a security measure. It avoids high-jacking a Jive session through a so-called XSS attack in some browsers. Since we are not accessing the REST endpoint through a browser, we can just ignore the &#8220;throw&#8221; line.</li>
<li>The links field contains the URI for the previous and next page. If an endpoint returns more than a page-full of objects, the &#8220;next&#8221; field can be used to go to the next set of objects. Similarly, the URI in the &#8220;previous&#8221; field can be used to go back in the data.</li>
<li>Under the &#8220;list&#8221; field, the actual data concerning a Jive resource is returned.</li>
<li>Each Jive object returned by the REST endpoints, contains a &#8220;resources&#8221; field. In the example we are looking at a &#8220;discussion&#8221; object. Under the resources field we find several links to related information. For example, the &#8220;attachments&#8221; field will show what actions (&#8220;POST&#8221; and &#8220;GET&#8221;) are allowed, and also the URI to access these attachments.</li>
<li>The returned discussion object has several fields that provide extra information. The object contains fields to indicate how many users are following the discussion, how many like a specific reply, when the discussion was created and last updated.</li>
<li>The &#8220;author&#8221; field provides information about the user that created the discussion. Again, the &#8220;resources&#8221; field provides links to access related information about the author.</li>
<li>The &#8220;content&#8221; of the discussion. Note that this is provided as HTML</li>
<li>Two important fields related to discussions are the &#8220;question&#8221; and &#8220;resolved&#8221; fields. The first one indicates if the discussion is actually marked as a question, the second one indicates if there has been an accepted answer to the discussion or not.</li>
<li>The &#8220;startIndex&#8221; field shows the index of the next reply in the discussion. This also allows us to determine how many answer there have already been to the discussion, just note that the index is zero-based</li>
<li>The &#8220;parent&#8221; for a discussion object is the place, or community in VMTN terminology, where the discussion was started.</li>
</ol>
<h2>The Script</h2>
<p>The script is in fact a module, named <a href="https://github.com/lucdekens/VMTNRest" target="_blank" rel="noopener noreferrer"><strong>VMTNRest</strong></a>. The module contains a number of functions to access VMTN communities, authors and discussions.</p>
<p>You always start off with the <strong>Initialize-VMTNRest</strong> cmdlet. This cmdlet sets some module-wide values, and originally it was the intention to allow the caller to pass credentials. But apparently the current Jive version doen&#8217;t allow REST API calls from &#8220;<strong>federated</strong>&#8221; users with <strong>Basic Authentication</strong>. See <a href="https://community.jivesoftware.com/thread/276827" target="_blank" rel="noopener noreferrer">here</a> and <a href="https://stackoverflow.com/questions/29377067/jive-rest-api-returning-code401-messagebad-credentials-using-basic-aut" target="_blank" rel="noopener noreferrer">here</a> for more information on that issue. I&#8217;m still looking for a possible bypass, but for now, the cmdlets in the VMTNRest module only allow access to the &#8220;<strong>public</strong>&#8221; VMTN resources. If you have access to <strong>private communities</strong>, I&#8217;m afraid that for now you will not be able to access these resources.</p>
<p>Another parameter that could be of use is the <strong>MaxCount</strong> parameter. It defines how many objects the REST API returns on one call. The default is 100, also the maximum the Jive software allows. You can set this to a number between 1 and 100.</p>
<p>The <strong>MaxSamples</strong> parameter, which is available on the other cmdlets in the VMTNRest module, defines the maximum total number of objects that are returned in one call to the cmdlet. This parameter is set by default to 100, but can be changed. Be warned though, there are a lot of objects available in some categories. You don&#8217;t want to wait for example till the REST API has returned all +3400000 author objects <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>The other three public cmdlets retrieve objects from the VMTN community. They are <strong>Get-VMTNAuthor</strong>, <strong>Get-VMTNCommunity</strong> and <strong>Get-VMTNContent</strong>. Some of these objects are quite rich  in content, as we will see in the next section.</p>
<h2>Use Cases</h2>
<p>As we said earlier, you always have to start with the Initialize-VMTNRest cmdlet. In the following example we will take all the defaults, and not use a proxy.</p>
<p>One way to get to know the VMTN platform, is to have a look which communities and groups are available. The following example uses one keywword, and yes, I might be a bit biased in my choice of examples <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

Get-VMTNCommunity -Community PowerCLI |
Select-Object -Property name,description,type</pre><p>This returns the following.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5761 size-large" src="https://www.lucd.info/wp-content/uploads/2017/12/sample-1-1024x127.png" alt="" width="770" height="95" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample-1-1024x127.png 1024w, https://www.lucd.info/wp-content/uploads/2017/12/sample-1-300x37.png 300w, https://www.lucd.info/wp-content/uploads/2017/12/sample-1-768x95.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/sample-1-720x89.png 720w, https://www.lucd.info/wp-content/uploads/2017/12/sample-1.png 1076w" sizes="auto, (max-width: 770px) 100vw, 770px" /></p>
<p>Note that &#8220;<strong>place</strong>&#8221; is the internal Jive name for what we know as a VMTN community. Also note that the keywork &#8220;PowerCLI&#8221; doesn&#8217;t seem to appear in the name of a returned community. The reason is that internally the REST API looks at more than just the name of a community.</p>
<p>If you want to look for an exact match in the name, you can use the <strong>ExactMatch</strong> parameter.</p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

Get-VMTNCommunity -Community 'VMware PowerCLI' -ExactMatch  |
Select-Object -Property name,description,type</pre><p>Now we only get the specific community we were looking for.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5762 size-full" src="https://www.lucd.info/wp-content/uploads/2017/12/sample2.png" alt="" width="826" height="85" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample2.png 826w, https://www.lucd.info/wp-content/uploads/2017/12/sample2-300x31.png 300w, https://www.lucd.info/wp-content/uploads/2017/12/sample2-768x79.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/sample2-720x74.png 720w" sizes="auto, (max-width: 826px) 100vw, 826px" /></p>
<p>Besides communities, there are also blogs and groups available in VMTN.</p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

Get-VMTNCommunity -Community PowerCLI -IncludeBlog -IncludeGroup |
Select-Object -Property name,type,description</pre><p>And we get entries that have &#8220;PowerCLI&#8221; in their name or description.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5763" src="https://www.lucd.info/wp-content/uploads/2017/12/sample-3.png" alt="" width="1278" height="200" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample-3.png 1278w, https://www.lucd.info/wp-content/uploads/2017/12/sample-3-300x47.png 300w, https://www.lucd.info/wp-content/uploads/2017/12/sample-3-768x120.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/sample-3-1024x160.png 1024w, https://www.lucd.info/wp-content/uploads/2017/12/sample-3-720x113.png 720w" sizes="auto, (max-width: 1278px) 100vw, 1278px" /></p>
<p>All the documents and entries in communities and blogs have an author. With the Get-VMTNAuthor we can explore those.</p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

Get-VMTNAuthor -Author lucd | 
Select displayName,id,
    @{N='Published';E={([DateTime]$_.published).ToLocalTime()}},
    @{N='Updated';E={([DateTime]$_.updated).ToLocalTime()}}</pre><p>This returns</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5764" src="https://www.lucd.info/wp-content/uploads/2017/12/sample-4.png" alt="" width="506" height="321" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample-4.png 506w, https://www.lucd.info/wp-content/uploads/2017/12/sample-4-300x190.png 300w" sizes="auto, (max-width: 506px) 100vw, 506px" /></p>
<p>The REST API looked for all authors whose name starts with &#8220;lucd&#8221;. But we also can go for an exact match.</p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

Get-VMTNAuthor -Author lucd -ExactMatch | 
Select displayName,id,
    @{N='Published';E={([DateTime]$_.published).ToLocalTime()}},
    @{N='Updated';E={([DateTime]$_.updated).ToLocalTime()}}</pre><p>And we get the single object back.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5766" src="https://www.lucd.info/wp-content/uploads/2017/12/sample-5.png" alt="" width="482" height="82" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample-5.png 482w, https://www.lucd.info/wp-content/uploads/2017/12/sample-5-300x51.png 300w" sizes="auto, (max-width: 482px) 100vw, 482px" /></p>
<p>We can also do some historic research with the DateTime parameters. Do we still have authors around that were created in the early days of VMTN. And we assume that the official start date was July 10th in 2003.</p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

$origin = Get-Date "10 Jul 2003"
Get-VMTNAuthor -CreatedAfter $origin -CreatedBefore $origin.AddDays(1) | 
Sort-Object -Property {[int]$_.id} |
Select-Object -First 5 -Property displayName,id,
        @{N='Points';E={$_.jive.level.points}},
        @{N='Published';E={([DateTime]$_.published).ToLocalTime()}} |
Format-Table -AutoSize</pre><p>Yup, still some of those first-day authors around.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5767" src="https://www.lucd.info/wp-content/uploads/2017/12/sample-6.png" alt="" width="342" height="125" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample-6.png 342w, https://www.lucd.info/wp-content/uploads/2017/12/sample-6-300x110.png 300w" sizes="auto, (max-width: 342px) 100vw, 342px" /></p>
<p>Just wonder what happened with ids 1 to 7 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Finally we get to the core of the VMTN communities, the discussions. Again, quite simple to query.</p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

Get-VMTNContent -Keyword 'New-OSCustomizationSpec' |
select subject,status,resolved,replycount,viewcount,
    @{N='Author';E={$_.author.displayName}},
    @{N='Location';E={$_.parentPlace.name}},
    @{N='Published';E={([DateTime]$_.published).ToLocalTime()}},
    @{N='LastActivity';E={([DateTime]$_.lastActivityDate).ToLocalTime()}} |
Format-Table -AutoSize</pre><p>And this returns 100 objects, remember, the default <strong>MaxSamples</strong>.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5769" src="https://www.lucd.info/wp-content/uploads/2017/12/sample-7.png" alt="" width="1993" height="609" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample-7.png 1993w, https://www.lucd.info/wp-content/uploads/2017/12/sample-7-300x92.png 300w, https://www.lucd.info/wp-content/uploads/2017/12/sample-7-768x235.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/sample-7-1024x313.png 1024w, https://www.lucd.info/wp-content/uploads/2017/12/sample-7-720x220.png 720w" sizes="auto, (max-width: 1993px) 100vw, 1993px" /></p>
<p>These &#8220;content&#8221; objects are very rich, but I leave that to you and Get-Member to discover.</p>
<p>As we stated earlier, with the cmdlet we can also search the blog posts and documents. Let&#8217;s check if someone blogged about VSAN in the last month.</p><pre class="urvanov-syntax-highlighter-plain-tag">Initialize-VMTNRest

$now = Get-Date

Get-VMTNContent -Keyword 'VSAN' -ContentType post -SearchSubjectOnly -Start $now.AddMonths(-1) | 
select subject,status,resolved,replycount,viewcount,
    @{N='Author';E={$_.author.displayName}},
    @{N='Location';E={$_.parentPlace.name}},
    @{N='Published';E={([DateTime]$_.published).ToLocalTime()}},
    @{N='LastActivity';E={([DateTime]$_.lastActivityDate).ToLocalTime()}} |
Format-Table -AutoSize</pre><p>And there we go.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5770" src="https://www.lucd.info/wp-content/uploads/2017/12/sample-8.png" alt="" width="1076" height="90" srcset="https://www.lucd.info/wp-content/uploads/2017/12/sample-8.png 1076w, https://www.lucd.info/wp-content/uploads/2017/12/sample-8-300x25.png 300w, https://www.lucd.info/wp-content/uploads/2017/12/sample-8-768x64.png 768w, https://www.lucd.info/wp-content/uploads/2017/12/sample-8-1024x86.png 1024w, https://www.lucd.info/wp-content/uploads/2017/12/sample-8-720x60.png 720w" sizes="auto, (max-width: 1076px) 100vw, 1076px" /></p>
<p>The functionality these cmdlets bring you is of course also available via a Web Browser and the Search functionality on the VMTN website. But with these cmdlets you can now automate some of your searches. You could for example schedule a script to check weekly if something was published about VSAN. Mail the report to yourself, and you can immediately see if you need to fire up your browser.</p>
<p>The cmdlets are just another way to access the information available in VMware&#8217;s VMTN Community, and seen the richness of the returned objects, you can go very far in this. Some examples are the InfoGraphs I ended up with in the end for my VMworld session.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5771 size-large" src="https://www.lucd.info/wp-content/uploads/2017/12/slide11-1024x683.jpg" alt="" width="770" height="514" srcset="https://www.lucd.info/wp-content/uploads/2017/12/slide11-1024x683.jpg 1024w, https://www.lucd.info/wp-content/uploads/2017/12/slide11-300x200.jpg 300w, https://www.lucd.info/wp-content/uploads/2017/12/slide11-768x512.jpg 768w, https://www.lucd.info/wp-content/uploads/2017/12/slide11-720x480.jpg 720w" sizes="auto, (max-width: 770px) 100vw, 770px" /></p>
<p>and</p>
<p><img loading="lazy" decoding="async" class="alignnone size-large wp-image-5772" src="https://www.lucd.info/wp-content/uploads/2017/12/slide12-1024x683.jpg" alt="" width="770" height="514" srcset="https://www.lucd.info/wp-content/uploads/2017/12/slide12-1024x683.jpg 1024w, https://www.lucd.info/wp-content/uploads/2017/12/slide12-300x200.jpg 300w, https://www.lucd.info/wp-content/uploads/2017/12/slide12-768x512.jpg 768w, https://www.lucd.info/wp-content/uploads/2017/12/slide12-720x480.jpg 720w" sizes="auto, (max-width: 770px) 100vw, 770px" /></p>
<p>If you have suggestions to improve or expand the VMTNRest module, feel free to contact me.</p>
<p>Enjoy!</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.lucd.info/2017/12/31/search-vmtn-rest-api/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Automate your VMTN search</title>
		<link>https://www.lucd.info/2012/02/29/automate-your-vmtn-search/</link>
					<comments>https://www.lucd.info/2012/02/29/automate-your-vmtn-search/#comments</comments>
		
		<dc:creator><![CDATA[LucD]]></dc:creator>
		<pubDate>Wed, 29 Feb 2012 21:26:54 +0000</pubDate>
				<category><![CDATA[PowerCLI]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[VMTN]]></category>
		<guid isPermaLink="false">http://www.lucd.info/?p=3963</guid>

					<description><![CDATA[Recently I had the pleasure of doing a guest post, called Finding your [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Recently I had the pleasure of doing a guest post, called <a href="https://blogs.vmware.com/vipowershell/2012/02/guest-post-finding-your-way-in-the-powercli-community.html" target="_blank">Finding your way in the PowerCLI Community,</a> on the <a href="https://blogs.vmware.com/vipowershell/" target="_blank">PowerCLI blog</a>. The subject of the post was how to find community threads, that might hold an answer to your question.</p>
<p>Now this wouldn&#8217;t be a PowerShell/PowerCLI blog, if I didn&#8217;t try to <strong>automate</strong> the procedure. And with a serious amount of <strong>RegEx</strong> involved, I was able to create some working code. Here it is, my <strong>Find-VMTNPowerCLI</strong> function.</p>
<p style="padding-left: 60px;"><a href="https://lucd.info/wp-content/uploads/2012/02/spyglass.gif"><img loading="lazy" decoding="async" class=" wp-image-3906 alignnone" title="variations" src="https://lucd.info/wp-content/uploads/2012/02/spyglass.gif" alt="" width="317" height="162" /></a></p>
<p><strong><span style="background-color: #ffff00;">Warning</span></strong>: pure <strong>PowerShell</strong>, no <strong>PowerCLI</strong> content !</p>
<p><span id="more-3963"></span></p>
<h2>The script</h2>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">function Find-VMTNPowerCLI{
&lt;#
.SYNOPSIS  Search the VMTN PowerCLI related communities
.DESCRIPTION The function automates the functionality that
  is available through the Search page
.NOTES  Author:  Luc Dekens
.PARAMETER Question
  The question as you would enter it on the VMTN Search page
.PARAMETER Start
  The start date of the period in which you are looking for
  threads that fitt your search.
  The default is December 24th 2007.
.PARAMETER Finish
  The start date of the period in which you are looking for
  threads that fitt your search.
  The default is now.
.PARAMETER ReplyStart
  The start date of the period in which you are looking for
  replies that fitt your search.
  The default is December 24th 2007.
.PARAMETER ReplyFinish
  The start date of the period in which you are looking for
  replies that fitt your search.
  The default is now.
.PARAMETER Author
  Filter the returned threads to those started by one of the
  authors.
.PARAMETER ReplyAuthor
  Filter the returned threads to those where the reply came
  from one of the authors.
.PARAMETER PowerCLI
  Switch, search the PowerCLI Community.
  The default for this switch is $true.
.PARAMETER Onyx
  Switch, search the Onyx Community.
  The default for this switch is $false.
.PARAMETER UpdateManager
  Switch, search the UpdateManager Community.
  The default for this switch is $false.
.PARAMETER PowerShellers
  Switch, search the PowerShellers group.
  The default for this switch is $false.
.PARAMETER AutomationTools
  Switch, search the AutomationTools COmmunity.
  The default for this switch is $false.
.PARAMETER Descending
  Switch, when true the returned threads will be
  in a descending Reply Date order.
  The default for this switch is $true.
.EXAMPLE
  PS&gt; Find-VMTNPowerCLI -Question 'svmotion thin'
.EXAMPLE
  PS&gt; Find-VMTNPowerCLI -Question '5.0.1' -PowerShellers
.EXAMPLE
  PS&gt; Find-VMTNPowerCLI -Question 'regex get-view' `
  &gt;&gt; -Start (Get-Date).AddDays(-14)
#&gt;

  param(
  [CmdletBinding()]
  [parameter(Mandatory = $true)]
  [string]$Question,
  [datetime]$Start = (New-Object DateTime -ArgumentList 2007,12,24),
  [datetime]$Finish = (Get-Date),
  [datetime]$ReplyStart = $Start,
  [datetime]$ReplyFinish = $Finish,
  [string[]]$Author,
  [string[]]$ReplyAuthor,
  [switch]$PowerCLI = $true,
  [switch]$Onyx,
  [switch]$UpdateManager,
  [switch]$PowerShellers,
  [switch]$AutomationTools,
  [switch]$Descending = $true
  )

  function Get-VMTNSearch{
    param(
    [string]$url,
    [switch]$Group
    )

    $pst = [TimeZoneInfo]::FindSystemTimeZoneById(&quot;Pacific Standard Time&quot;)
    $t0 = Get-Date
    $t1 = [TimeZoneInfo]::ConvertTime($t0,$pst)
    $tdiff = $t0 - $t1

    $regBodyText = [regex]'(?s)\[DocumentBodyStart.*?--&gt;(?&lt;bodyText&gt;.*)&lt;!--'
    $strAnswerAuthorGroup = 'jive-thread-reply jive-thread-reply-alt  clearfix[\w\W]*?xxxxxxx[\w\W]*?&lt;a href=&quot;/people/(?&lt;user&gt;.*)&quot;'
    $strAnswerAuthorOther = '&lt;a name=&quot;xxxxxxx[\w\W]*?&lt;a href=&quot;/people/(?&lt;user&gt;.*)&quot;'
    $regThreadAuthor = [regex]'jive-thread-post-body[\w\W]*?&lt;a href=&quot;/people/(?&lt;user&gt;.*)&quot;'
    $regThreadDate = [regex]'jive-thread-reply-date[\w\W]*?&lt;span&gt;(?&lt;threaddate&gt;.*?)&lt;/span&gt;'
    $regReplies = [regex]'(?&lt;replies&gt;\d*) Replies'

    $web = New-Object System.Net.WebClient
    $answerFeed = [[xml]]$web.DownloadString($url)
    $answerFeed.rss.channel.item |
    Sort-Object -Property {[datetime]$_.pubDate} -Descending |
    Select @{N=&quot;ReplyDate&quot;;E={[datetime]$_.pubDate}}, Title,
    @{N=&quot;Text&quot;;E={
        $bodyText = &quot;&quot;
        if($_.InnerText -match $regBodyText){
          $bodyText = $matches['bodyText']
          $bodyText = $bodyText -replace &quot;&lt;/p&gt;|&lt;br/&gt;&quot;,&quot;`n&quot;
          $bodyText = $bodyText -replace '&lt;blockquote class=&quot;jive-quote&quot;&gt;|&lt;/blockquote&gt;'
          $bodyText = $bodyText -replace &quot;&lt;.*?&gt;&quot;
          $bodyText = $bodyText -replace &quot;&amp;gt;&quot;,&quot;&gt;&quot;
          $bodyText = $bodyText -replace &quot;&amp;#160;&quot;,&quot;`t&quot;
        }
        $bodyText}},
    @{N=&quot;Reply&quot;;E={
        Set-Variable -Name page -Value $web.DownloadString($_.Link) -Scope 1
        $bookmark = $_.Link.Split('#')[1]
        if($group){
          $regAnswerAuthor = [regex]$strAnswerAuthorGroup.Replace('xxxxxxx',$bookmark)
        }
        else{
          $regAnswerAuthor = [regex]$strAnswerAuthorOther.Replace('xxxxxxx',$bookmark)
        }
        $user = &quot;&quot;
        if($page -match $regAnswerAuthor){
          $user = $matches['user']
        }
        [System.Web.HttpUtility]::UrlDecode($user)
      }},
    @{N=&quot;Poster&quot;;E={
        $user = &quot;&quot;
        if($page -match $regThreadAuthor){
          $user = $matches['user']
        }
        [System.Web.HttpUtility]::UrlDecode($user)
      }},
    @{N=&quot;ThreadDate&quot;;E={
        $threadDate = &quot;&quot;
        if($page -match $regThreadDate){
          $threadDate = ([datetime]$matches['threaddate']).Add($tdiff)
        }
        $threadDate
      }},
    @{N=&quot;Replies&quot;;E={
        if($page -match $regReplies){
          $matches['replies']
        }
        else{0}
      }},
    Link

    $web.Dispose()
  }

  $containerPowerCLI = 2530
  $containerOnyx = 3498
  $containerUpdateManager = 3482
  $containerAutomationTools = 3102
  $containerPowerShellers = 1013
  $typePowerShellers = 700

  $searchUrl = &quot;https://communities.vmware.com/community/feeds/search&quot;
  $questionText = &quot;q=&quot; + [System.Web.HttpUtility]::UrlEncode($Question)
  $peopleEnabled = &quot;peopleEnabled=true&quot;
  $containerType = &quot;containerType=14&quot;
  $container = &quot;container=$containerPowerCLI&quot;
  $dateRange = &quot;dateRange=all&quot;
  $numResults = &quot;numResults=&quot; + [int]::MaxValue

  $query = $questionText + &quot;&amp;&quot; + $peopleEnabled + &quot;&amp;&quot; + $containerType +
  &quot;&amp;&quot; + $container + &quot;&amp;&quot; + $dateRange + &quot;&amp;&quot; + $numResults
  $url = $searchUrl + &quot;?&quot; + $query

  $result = @()
  if($PowerCLI){
     $result += Get-VMTNSearch -Url $url
  }
  if($Onyx){
    $url = $url -replace &quot;(container=)(\d+)&quot;,&quot;`${1}$containerOnyx&quot;
    $result += Get-VMTNSearch -Url $url
  }
  if($UpdateManager){
    $url = $url -replace &quot;(container=)(\d+)&quot;,&quot;`${1}$containerUpdateManager&quot;
     $result += Get-VMTNSearch -Url $url
  }
  if($PowerShellers){
    $url = $url -replace &quot;(container=)(\d+)&quot;,&quot;`${1}$containerPowerShellers&quot;
    $url = $url -replace &quot;(containerType=)(\d+)&quot;,&quot;`${1}$typePowerShellers&quot;
    $result += Get-VMTNSearch -Url $url -Group
  }

  $condition = '$_.ReplyDate -ge $ReplyStart -and $_.ReplyDate -le $ReplyFinish -and'
  $condition += '  $_.ThreadDate -ge $Start -and $_.ThreadDate -le $Finish'
  if($Author){
    $condition += ' -and $Author -contains $_.Poster'
  }
  if($ReplyAuthor){
    $condition += ' -and $ReplyAuthor -contains $_.Reply'
  }
  $sblock = $executioncontext.InvokeCommand.NewScriptBlock($condition)
  $result | where {&amp;$sblock} | Sort-Object -Property ReplyDate -Descending:$Descending
}</pre><p></p>
<h4>Annotations</h4>
<p><strong>Line 63</strong>: The first thread in the PowerCLI Community dates from December 24th 2007. No reason to go further back in time <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><strong>Line 77-149</strong>: An internal helper function. This is the real workhorse of the function, in here all the RegEx mgic takes place.</p>
<p><strong>Line 80</strong>: The way <strong>Jive</strong> returns results for a community or a group is slightly different. Hence the Group switch, which will allow the function Get-VMTNSearch to act differently for the PowerShellers group.</p>
<p><strong>Line 83-86</strong>: The ThreadData is returned in <strong>PST</strong> time (I suppose that is where the VMTN servers are located). These lines will calculate the time difference between the location where you run the script and PST time.</p>
<p><strong>Line 88-93</strong>: The RegEx expressions that will be used in the function to extract the desired fields.</p>
<p><strong>Line 96</strong>: The URL, which is passed from the calling function, contains the actual Search keywords. Here we download the results from the search and convert it to an XML list for further handling.</p>
<p><strong>Line 97</strong>: The individual &#8216;items&#8217; from the search result are retrieved and used to extract the data.</p>
<p><strong>Line 103-108</strong>: The content of the reply post is interspersed with HTML code. The series of <strong>-Replace</strong> operators will convert and filter away the HTML tags.</p>
<p><strong>Line 112</strong>: The function fetches the complete page for the thread. This required for extracting the properties that follow. The <strong>-Scope 1</strong> parameter makes sure that the $page variable is available outside the calculated property code block.</p>
<p><strong>Line 113-119</strong>: The RegEx string contains the bookmark for the specific reply we are looking at. That is why the script updates the RegEx string with the bookmark. The Reply field has a different layout depending if it comes from a Community or a Group.</p>
<p><strong>Line 124,131</strong>: Some user names might contain blanks or other special characters, to avoid displaying the Javascript encoding for these special characters, the property value is decoded.</p>
<p><strong>Line 136</strong>: The thread date is returned in PST time (see above). This converts the datetime value to your local time.</p>
<p><strong>Line 151-155</strong>: All the VMTN Communities have a specific ID. This ID needs to be used in the search URL.</p>
<p><strong>Line 156</strong>: The PowerShellers group has a specific type, different from the Community type.</p>
<p><strong>Line 158</strong>: The basic Search page URL</p>
<p><strong>Line 159</strong>: The search URL needs to have all special characters converted.</p>
<p><strong>Line 160-164</strong>: The other parameters passed on the search URL</p>
<p><strong>Line 164</strong>: On the Search page, the results are returned in batches of 10, 15 or 30. In the function we want all the results in one go, hence the maximum [int] value.</p>
<p><strong>Line 171-186</strong>: The Get-VMTNSearch internal function is called for each of the selected communities.</p>
<p><strong>Line 188-195</strong>: All the selected conditions are stored in a [string]</p>
<p><strong>Line 196</strong>: The string with the conditions is converted in a code block</p>
<p><strong>Line 197</strong>: The generated code block is used in the Where-clause to filter the results according to the passed parameters.</p>
<h2>Sample usage</h2>
<p>The function is quite simple to use. The Question parameter accepts the exact same search strings as you can enter on the <strong>Search page</strong>. See the VMTN <a href="https://communities.vmware.com/search-tips.jspa" target="_blank">Search Tips</a> for the details.</p>
<p>A simple example that will look for the keyword &#8216;<em><strong>move-vmthin</strong></em>&#8216; in the <strong>PowerCLI Community</strong>.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$qtext = &quot;move-vmthin&quot;

Find-VMTNPowerCLI -Question $qtext |
Export-Csv .\search-results.csv -NoTypeInformation -UseCulture</pre><p></p>
<p>The resulting CSV file looks like this</p>
<p><a href="https://lucd.info/wp-content/uploads/2012/02/search1.png"><img loading="lazy" decoding="async" class=" wp-image-3906 alignnone" title="Search 1" src="https://lucd.info/wp-content/uploads/2012/02/search1.png" alt="" width="940" height="146" /></a></p>
<p>Note that in the <strong>Text</strong> column you can find the complete content of the reply. This can make it quite easy to copy code to your favorite PowerShell editor.</p>
<p><a href="https://lucd.info/wp-content/uploads/2012/02/search2.png"><img loading="lazy" decoding="async" class=" wp-image-3906 alignnone" title="Search 1 Text" src="https://lucd.info/wp-content/uploads/2012/02/search2.png" alt="" width="804" height="281" /></a></p>
<p>The next example will look for the text &#8216;<em><strong>baseline groups remediate-inventory</strong></em>&#8216; only in the <strong>Update Manager PowerCLI</strong> Community.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$qtext = 'baseline groups remediate-inventory'

Find-VMTNPowerCLI -Question $qtext -UpdateManager -PowerCLI:$false |
Export-Csv D:\Tools\PowerShell\Scripts\search-results.csv -NoTypeInformation -UseCulture</pre><p></p>
<p>The result</p>
<p><a href="https://lucd.info/wp-content/uploads/2012/02/search3.png"><img loading="lazy" decoding="async" class=" wp-image-3906 alignnone" title="Search 2 Text" src="https://lucd.info/wp-content/uploads/2012/02/search3.png" alt="" width="748" height="73" /></a></p>
<p>With the search functionality, you could for example look for replies that contain functions. Searching for the words &#8216;<em><strong>function param</strong></em>&#8216; we would find quite a number of replies that contain code.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$qtext = &quot;function param&quot;

Find-VMTNPowerCLI -Question $qtext |
Export-Csv D:\Tools\PowerShell\Scripts\search-results.csv -NoTypeInformation -UseCulture</pre><p></p>
<p>The resulting CSV file contains 167 rows. Perhaps a bit too much. So let&#8217;s limit the replies to a specific <strong>time period</strong>. We only look for replies after <strong>September 1st 2011</strong>.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$qtext = &quot;function param&quot;
$start = Get-Date -Year 2011 -Month 9 -Day 1

Find-VMTNPowerCLI -Question $qtext -ReplyStart $start |
Export-Csv D:\Tools\PowerShell\Scripts\search-results.csv -NoTypeInformation -UseCulture</pre><p></p>
<p>Much better, now we find 23 replies, with recent code.</p>
<p><a href="https://lucd.info/wp-content/uploads/2012/02/search4.png"><img loading="lazy" decoding="async" class=" wp-image-3906 alignnone" title="Search 3 Text" src="https://lucd.info/wp-content/uploads/2012/02/search4.png" alt="" width="778" height="405" /></a></p>
<h2>A word of warning</h2>
<p>I&#8217;m pretty sure there are some threads around that will break the function. With so many threads and replies in these very active PowerCLI related communities and groups, there are bound to be some that I didn&#8217;t encounter during my tests and that will break the function.</p>
<p>Should you encounter something like that, feel free to post the parameters in the comments for this post and I will try to fix the function.</p>
<p>Enjoy !</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.lucd.info/2012/02/29/automate-your-vmtn-search/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
