OpsMgr Dashboard Fun: Google Maps

7 minute read

I am really excited about the 2 new PowerShell dashboard widget released in OpsMgr 2012 R2 UR2. PowerShell has always been my favourite scripting language, something I have been using on a daily basis since 2008. In my opinion, the opportunities are endless when having the ability to execute PowerShell scripts within an OpsMgr dashboard. I will start posting my ideas in this blog.

Background

For those who don’t know me, I work for an Australian retailer which has 3 brands (supermarkets, service stations and liquor stores) with totally over 2000 stores across the country. Pretty much every Windows device in the stores are being managed by System Center. Because of the nature of the environment we are in, in the past, there were ideas tossing around in the office that people really like to have some kind of map dashboard for OpsMgr, and we have trailed / tested different solutions. Although there are 3rd party solutions out there, yesterday, I have spent couple of hours and created a dashboard like this:

image

This dashboard contains:

  • Top Left: State widget for a customized class called “TYANG Remote Computer”, which is based on Windows Computer class.
  • Bottom Left: Contextual PowerShell Grid widget displays health state of all related objects for “TYANG Remote Computers”
  • Right: Contextual PowerShell Web Browser widget that pin-points the computer location on Google Maps.

In Action:

I’ll now go through the steps I took to make this dashboard work. the management packs I used in the demo can also be downloaded from the link at the end of this post.

Instructions

Step 01. Create a management pack to define and discover the custom Windows Computer class.

I Named this management pack “Demo.Remote.Computers”. I basically created a customized Windows Computer class with 4 additional properties:

  • Street
  • City (aka Suburb as what we call in Australia)
  • State
  • Country

image

I then created a registry key and stored these property values in the key:

image

After creating the registry key on few machines, I then created a filtered registry discovery workflow in the MP. It targets Windows Computer class and it is looking for this key. It also maps the 4 reg key values I created to the class properties.

Lastly, before I sealed the MP, I also created a folder and a state view for this custom class. The Accessibility of the folder is set to “Public” – so later on I can place the dashboard under this folder from a separate MP.

image

Step 02. Create the dashboard

Now that the class is defined and discovered, I can move on to the dashboard. To create the dashboard, firstly, I created a brand new MP from the Operations console, and called it “Demo Remote Computer Dashboard” with the ID “Demo.Remote.Computer.Dashboard”. When the unsealed MP is created in the operations console, a folder is automatically created with the MP. I will place the dashboard under this folder (for now):

image

I gave the dashboard a name and chose an appropriate dashboard layout :

SNAGHTML22e2dfb6SNAGHTML22e37454

I added a state widget for the top left pane

SNAGHTML22e4fb14

Gave it a name: “Remote Computers”

SNAGHTML22e5ef28

Choose the class I have defined in Step 1

SNAGHTML22e6ece1

I want to display all instances, so I did not select anything in the Criteria step:

SNAGHTML22e82adf

I defined what I property that I want to display, and how to sort the instances:

image

Then click Next and Create to create the widget.

image

Next, I’ll create a PowerShell Grid contextual widget in the bottom right section to display the health of each related components.

Choose “PowerShell Grid Widget”

SNAGHTML22ed3e40

Name: “Components”

SNAGHTML22ee6098

Add the script below to the script section:

SNAGHTML22ef9a12

Param($globalSelectedItems)
foreach ($globalSelectedItem in $globalSelectedItems)
{
  $globalSelectedItemInstance = Get-SCOMClassInstance -Id $globalSelectedItem["Id"]
  foreach ($relatedItem in $globalSelectedItemInstance.GetRelatedMonitoringObjects())
  {
    $ClassName = $relatedItem.GetMonitoringclasses()[0].DisplayName
    $dataObject = $ScriptContext.CreateFromObject($relatedItem, "Id=Id,State=HealthState,DisplayName=DisplayName,FullName=FullName", $null)
    $dataObject["ParentRelatedObject"] = $globalSelectedItemInstance.DisplayName
    $ScriptContext.ReturnCollection.Add($dataObject)
  }
}

Click Next and Create to create the widget.

SNAGHTML22f0d6d8

Lastly, I’ll create a PoweShell Web Browser contextual widget for the map on the right section.

Choose PowerShell Web Browser Widget

SNAGHTML22f274d8

Name it “Map”

SNAGHTML22f3613c

Copy the script below to the script section:

SNAGHTML22f4ac2b

Param($globalSelectedItems)
$dataObject = $ScriptContext.CreateInstance("xsd://Microsoft.SystemCenter.Visualization.Component.Library!Microsoft.SystemCenter.Visualization.Component.Library.WebBrowser.Schema/Request")
$dataObject["BaseUrl"]="http://maps.google.com/maps"
$parameterCollection = $ScriptContext.CreateCollection("xsd://Microsoft.SystemCenter.Visualization.Component.Library!Microsoft.SystemCenter.Visualization.Component.Library.WebBrowser.Schema/UrlParameter[]")
foreach ($globalSelectedItem in $globalSelectedItems)
{
  $globalSelectedItemInstance = Get-SCOMClassInstance -Id $globalSelectedItem["Id"]
  $StreetProperty = $globalSelectedItemInstance.GetMonitoringProperties() | Where-Object {$_.name -match "Street"}
  $CityProperty = $globalSelectedItemInstance.GetMonitoringProperties() | Where-Object {$_.name -match "City"}
  $StateProperty = $globalSelectedItemInstance.GetMonitoringProperties() | Where-Object {$_.name -match "State"}
  $CountryProperty = $globalSelectedItemInstance.GetMonitoringProperties() | Where-Object {$_.name -match "Country"}
  $Street = $globalSelectedItemInstance.GetMonitoringPropertyValue($StreetProperty)
  $City = $globalSelectedItemInstance.GetMonitoringPropertyValue($CityProperty)
  $State = $globalSelectedItemInstance.GetMonitoringPropertyValue($StateProperty)
  $Country = $globalSelectedItemInstance.GetMonitoringPropertyValue($CountryProperty)
  $parameter = $ScriptContext.CreateInstance("xsd://Microsoft.SystemCenter.Visualization.Component.Library!Microsoft.SystemCenter.Visualization.Component.Library.WebBrowser.Schema/UrlParameter")
  $parameter["Name"] = "q"
  $parameter["Value"] = "$street $City $state $Country"
  $parameterCollection.Add($parameter)
}
$dataObject["Parameters"]= $parameterCollection
$ScriptContext.ReturnCollection.Add($dataObject)

Click Next and Create to create the widget.

The dashboard should be fully functional by now.

image

You can stop now, or continue on to the next step to use the GTM tool to generalize the dashboard MP – if you want to use this dashboard in other management groups.

Step 03: Generalizing the Dashboard MP

Firstly, export the dashboard MP, but do not delete it from the management group after export.

Run the GTMTool.exe against the exported MP. When asked if I want to create a task pane dashboard, answer “Y” and enter the name of the MP I created in step 01 (“Demo.Remote.Computers”).

image

Although it’s not required, but I also opened the MP generated by the GTMTool.exe, replaced all the “UIGenerated” strings with something meaningful.

Before:

image

After:

image

Lastly, delete the old dashboard MP in OpsMgr, and import the updated one. The dashboard can now be found under the folder from the MP created in step 01.

image

Issues I experienced

  1. Google Maps VS. Bing Maps

Someone may want to ask, why did I choose Google Maps rather than Microsoft’s Bing Maps. Well, I’m not sure about other countries, but couple of years ago when I was testing a well known OpsMgr map dashboard, which uses Bing Map (you probably know which one I’m talking about), I found the mapping data for Australia is very inaccurate.

For example, when I searched my local supermarket using address, Google Maps had no problem pin-pointing it in the map, but Bing maps could not find it:

Google Maps:

image

Bing Maps:

image

You can argue that I live in a Melbourne’s outer suburb, it is approx. 50km away from CBD and I can see horses and cows on a daily basis. Bing can be accurate for metropolitan areas or famous tourist attractions.

i.e. the supermarket located in Bondi Junction, NSW, near the famous Bondi Beach:

Google Maps finds it:

image

Bing Maps also finds it:

image

But for me employer, who operates all over Australia including areas very remote, it’s clearly an issue – unless we use map co-ordinates instead of addresses.

  1. Google Maps Script Error:

While I was configuring Google Map widget, I also had an issue that I always get a script execution error from IE:

image

After spending some time googling this error, I learned Google does not work well with certain versions of IE. This leads to an issue that could be a common issue with the PowerShell Web Browser Widget. I managed to identify and fix the error, I’ll cover the issue and the fix in a separate post, because I believe this error can happen for other web sites.

  1. Google Maps left pane

I tried to find a way to disable it, but in many online forums, people said there is no way to disable it unless use it in an iframe with the parameter “out=embed” in the URL.

image

I’m not a web developer, but I’m guessing if I develop a web page on a web server to host such an iframe, I should be able to remove it? it’s just a thought, I haven’t looked into it.

Anyways, after playing with it for a while, I don’t really mind clicking the arrow to minimise the left pane every time, having the left pane there can be handy sometimes as I can also use the “Get Directions” function as I demonstrated in the video.

Conclusion

Overall, I spent more time trying to get Google Maps working in the widget than time creating the management pack and dashboard. The management packs can be downloaded HERE.

Please keep in mind the MP that defines and discovers your classes must be sealed so other MPs can reference it. I’ve included both sealed and unsealed version of this MP, if you want to test it out in your environment, please make sure you used the sealed version (Demo.Remote.Computers.mp).

I did not seal the dashboard MP so it is easier for you to see what’s under the hood.

Leave a comment