The other day Don Jones tweeted about find a PowerShell user group. In case you didn't know, just about every user group associated with PowerShell can be found online at http://powershellgroup.org. This is a terrific resource for finding a user group near you. Of course, Twitter being what it is someone joked about the lack of a Get-PSUserGroup cmdlet. So, taking the joke as a challenge I built on. Don also was going to build something but I haven't seen what he came up with. I suspect it will be similar to mine.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Because we there is a web site, we can scrape it with Invoke-WebRequest.
$URL = http://powershellgroup.org/og
$r = Invoke-WebRequest $url
Instead of trying to parse the document object model (DOM), the resulting object has a property called AllElements which is exactly what the name implies. I had to look at the source HTML on the page to identify the elements I needed to reference. Since it seemed I could get what I want via an HTML class, I grouped the elements by class and turned it into a hashtable.
$c = $r.AllElements | group class -AsHashTable -AsString

I opted for a hashtable to make it easier to get all the elements for a given class. For example, I knew the 'views-field views-field-title' class would give me the name of each group.
$c.'views-field views-field-title'

Likewise I knew the 'views-field views-field-description' class would provide a description.
$c.'views-field views-field-description'

Knowing what each object looked like, you could also pipe to Get-Member to discover property names, made it easy to extract the relevant information.
#get total group count less one for the header
$count = ($c.'views-field views-field-description'.count)
for ($i = 1; $i -lt $count; $i++) {
$groupname = $c.'views-field views-field-title'[$i].innertext
$description = $c.'views-field views-field-description'[$i].InnerText
[pscustomobject]@{
Name = $groupname
Description = $description
}
}

Once I had the core concepts down, I built an advanced function around them called Get-PSUserGroup.
Function Get-PSUserGroup {
<#
.Synopsis
Get PowerShell User Groups
.Description
This command uses Invoke-Webrequest to retrieve user group information from PowerShellGroup.org. This command has no parameters.
.Example
PS C:\> get-psusergroup
Name : Central Texas Powershell Users Group
Description : Powershell Users Group in Central Texas
Contact : crshnbrn
MemberCount : 3
Status : Join
Link : http://powershellgroup.org/CentralTexas%20-%20Austin
Name : Strasbourg PowerShell User Group
Description : Strasbourg PowerShell User Group
Contact : stephanevg
MemberCount : 27
Status : Request membership
Link : http://powershellgroup.org/strasbourg
Name : Basel PowerShell User Group
Description : Basel PowerShell User Group
Contact : stephanevg
MemberCount : 26
Status : Request membership
Link : http://powershellgroup.org/basel
...
.Link
Get-PSUserGroupDetail
Invoke-Webrequest
#>
[cmdletbinding()]
Param()
#define base URL
[string]$URL = "http://powershellgroup.org/og"
write-Verbose "Retrieving group data from $url"
Try {
$r = Invoke-WebRequest $url -ErrorAction Stop
}
Catch {
Throw $_.Exception.message
}
If ($r) {
Write-Verbose "Processing results"
$c = $r.AllElements | group class -AsHashTable -AsString
#get total group count less one for the header
$count = ($c.'views-field views-field-description'.count)
Write-Verbose "Found $($count -1) groups"
#regular expression for parsing out the HREF link
[regex]$rx='<A href="(?<href>/\S+)"'
#enumerate entries, skipping the first one which is a header
for ($i = 1; $i -lt $count; $i++) {
$groupname = $c.'views-field views-field-title'[$i].innertext
#get link to the group page
$href = $rx.match($c.'views-field views-field-title'[$i].innerhtml).Groups["href"].Value
$link = "http://powershellgroup.org{0}" -f $href
#write a custom object to the pipeline for each group
[pscustomobject]@{
Name = $groupname
Description = $c.'views-field views-field-description'[$i].InnerText
Contact = $c.'views-field views-field-name'[$i].innertext
MemberCount = $c.'views-field views-field-member-count'[$i].InnerText
Status = $c.'views-field views-field-subscribe'[$i].InnerText
Link = $Link
}
} #for
} #if $r
} #end function
The command doesn't take any parameters and simply returns high level information about each group.

The pipelined object includes a link to the group's page which means you could try something like this:
get-psusergroup | out-gridview -title "Select a group" -PassThru | foreach { start $_.link}
All of the groups are sent to Out-GridView.

Select one or more groups and each link should open in your browser. Now you have no excuse for not finding a PowerShell User Group. And if here isn't one near you, start it!
I have some other interesting things on this topic, but I'll save those for another day. Enjoy!!

Scraping pages with PowerShell is good fun. I remember starting to build a solution in Visual Studio back in the day to monitor an auction site for interesting products. It’s more flexible with PowerShell as you can just run it as a scheduled task and make changes to it as required.
What’s your opinion on this?
http://programmers.stackexchange.com/questions/18454/should-i-return-from-a-function-early-or-use-an-if-statement
I’d normally write:
If (-not $r) {return}That way the bulk of the code isn’t wrapped in an IF statement. Makes it easier to read. It’s a habit I got into years ago whilst coding in VS with the ReSharper extension enabled.
Cheers,
Daniel
I tend to do the opposite:
if ($data) {
….
}
Presumably I’ve used a Try/Catch statement earlier to define $data. Depending on the task, I may or may not use an else statement to provide information that $data was empty.