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:
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.