Advanced example using PowerShell and the OpsMgr SDK: Creating and Updating Groups
Several months ago, there was a request in the Microsoft OpsMgr PowerShell newsgroup where someone was asking if PowerShell provided functionality for working with OpsMgr groups.
I definitely wanted to help out. I searched around a bit, and finally this post by Jakub Olesky here http://blogs.msdn.com/jakuboleksy/archive/2006/11/15/creating-and-updating-groups.aspx. That posting was a little bit intimidating to say the least, at the time. I asked around for some help and Stefan Stranger (http://blogs.technet.com/stefan_stranger/) came to the rescue. He modified Jakub’s code and created a working console application (the code was blogged, but the post is no longer available).
Recently, I finally got back on track with trying to port Jakub’s code to pure PowerShell (but still using the OpsMgr SDK).
At first, I tried to do something with PowerShell “here-string” (see this link or others for more information: http://www.microsoft.com/technet/scriptcenter/resources/pstips/jun07/pstip0629.mspx), but that wasn’t going so well. Oisin Grehan (http://www.nivot.org/) pointed out to me on a private list that a here-string was not the best approach as it was not the same as the C# syntax used by Jakub. So I went down the path of a MSDN article (http://msdn.microsoft.com/en-us/library/bb960490.aspx) that also was about creating OpsMgr groups, except that it used XML to create the strings required to create and edit the groups. After a lot of tinkering, I finally got my code to work.
In this particular blog post and attached script, you’ll see where I used XML to create some objects that will be used to create and edit the groups. Just after I create the XML object, I essentially just extract a simple string from inside the outer XML nodes. In the next week or so, I’m going to break down this script in this post into two pieces, I will make it more generic, and will go straight with using more simple string objects, instead of using XML.
Now, I’ve commented some sections of the code. You may note that there are 2 major sections: create the group, and update the group. I’ll blog more about each of these steps in the next week or so, where I’ll use the code below to create more generic PowerShell scripts that you can use for your next automation tasks.
If you attempt to run the code as-is, it will create a new group for you in your Operations Manger console named “Jakub@Work Sample All Computers Group”. The script will also assign all the members of your “Windows Computer” class to the group. There is a particular node ID that is excluded in the XML below, which can be pretty much ignored.
**CAUTION: This should only be run in a test environment. I do not take any responsibility for any issues this cause may cause. This code is provided as-is without any kind of warranty.**
Enough talking, here’s most of Jakub’s code translated into PowerShell. There are some long strings in here, so keep an eye out for line wrap.
#————–Begin Sample Script—————————
# Create a connection to the local SDK service.
# Must be run on the RMS.
$mg = New-Object Microsoft.EnterpriseManagement.ManagementGroup(”localhost”)
# Create an XML object which will define the members will be added to the group.
# In the end, the XML won’t be used, but just a string object.
$document=new-object System.Xml.XMLDocument
$rootElement = $document.CreateElement(”Configuration”)
$document.AppendChild($rootElement)
$membershipRuleElement = $document.CreateElement(”MembershipRule”)
$membershipClassElement = $document.CreateElement(”MonitoringClass”)
$membershipRelationshipElement = $document.CreateElement(”RelationshipClass”)
$membershipClassElement.set_InnerText(”`$MPElement[Name=`"Windows!Microsoft.Windows.Computer`"]`$”)
$membershipRelationshipElement.set_InnerText(”`$MPElement[Name=`"InstanceGroup!Microsoft.SystemCenter.InstanceGroupContainsEntities`"]`$”)
$rootElement.AppendChild($membershipRuleElement)
$membershipRuleElement.AppendChild($membershipClassElement);
$membershipRuleElement.AppendChild($membershipRelationshipElement);
$formula=$rootElement.get_InnerXml()
# Create the custom monitoring object group.
$allComputersGroup = new-object Microsoft.EnterpriseManagement.Monitoring.CustomMonitoringObjectGroup(”Jakub.At.Work.Namespace”,”AllComputerGroup”,”Jakub@Work Sample All Computers Group”,$formula)
# Get the default management pack.
$defaultManagementPack = $mg.GetManagementPacks(”Microsoft.SystemCenter.OperationsManager.DefaultUser”)[0]
# Get the management packs for references.
$windowsManagementPack = $mg.GetManagementPack([Microsoft.EnterpriseManagement.Configuration.SystemManagementPack]::Windows)
$instanceGroupManagementPack = $mg.GetManagementPack([Microsoft.EnterpriseManagement.Configuration.SystemManagementPack]::Group)
$newReferences = new-object Microsoft.EnterpriseManagement.Configuration.ManagementPackReferenceCollection
$newReferences.Add(”Windows”,$windowsManagementPack)
$newReferences.Add(”InstanceGroup”,$instanceGroupManagementPack)
# Create the new group.
$defaultManagementPack.InsertCustomMonitoringObjectGroup($allComputersGroup,$newReferences)
# The new group is created…
# Moving on to editing the group now…
# Get the class that represents the new group.
$myNewGroup = $mg.GetMonitoringClasses(”Jakub.At.Work.Namespace.AllComputerGroup”)[0]
# Get the discovery rule that populates the group.
$groupPopulateDiscovery = $myNewGroup.GetMonitoringDiscoveries()[0]
# Create an XML object which will the configuration of the group.
# In the end, the XML won’t be used, but just a string object.
$document=new-object System.Xml.XMLDocument
$rootElement=$document.CreateElement(”Configuration”)
$document.AppendChild($rootElement)
$ruleIdElement=$document.CreateElement(”RuleId”)
$groupInstanceElement = $document.CreateElement(”GroupInstanceId”)
$membershipRulesElement = $document.CreateElement(”MembershipRules”)
$membershipRuleElement = $document.CreateElement(”MembershipRule”)
$membershipClassElement = $document.CreateElement(”MonitoringClass”)
$membershipRelationshipElement = $document.CreateElement(”RelationshipClass”)
$excludeListElement = $document.CreateElement(”ExcludeList”)
$monitoringObjectIdElement = $document.CreateElement(”MonitoringObjectId”)
$ruleIdElement.set_InnerText(”`$MPElement`$”)
$groupInstanceElement.set_InnerText(”`$MPElement[Name=`"Jakub.At.Work.Namespace.AllComputerGroup`"]`$”)
$membershipClassElement.set_InnerText(”`$MPElement[Name=`"Windows!Microsoft.Windows.Computer`"]`$”)
$membershipRelationshipElement.set_InnerText(”`$MPElement[Name=`"InstanceGroup!Microsoft.SystemCenter.InstanceGroupContainsEntities`"]`$”)
$monitoringObjectIdElement.set_InnerText(”f5E5F15E-3D7D-1839-F4C6-13E36BCD982a”)
$rootElement.AppendChild($ruleIdElement)
$rootElement.AppendChild($groupInstanceElement)
$excludeListElement.AppendChild($monitoringObjectIdElement)
$membershipRuleElement.AppendChild($membershipClassElement)
$membershipRuleElement.AppendChild($membershipRelationshipElement)
$membershipRuleElement.AppendChild($excludeListElement)
$membershipRulesElement.AppendChild($membershipRuleElement)
$rootElement.AppendChild($membershipRulesElement)
$newconfiguration=$rootElement.get_InnerXml()
# Update the group membership for the new group.
$groupPopulateDiscovery.Status = [microsoft.enterprisemanagement.configuration.ManagementPackElementStatus]::PendingUpdate
$groupPopulateDiscovery.DataSource.Configuration = $newConfiguration
$groupPopulateDiscovery.GetManagementPack().AcceptChanges()
#———-End Sample Script————–
December 3rd, 2008 at 3:48 pm
Hi Marco,
I published that old post on my Microsoft Weblog. You can find it here.
http://blogs.technet.com/stefan_stranger/archive/2008/12/03/old-blog-post-about-compiling-commandline-application-for-creating-and-updating-groups.aspx
Regards,
Stefan Stranger
December 13th, 2008 at 3:08 am
What is still “intimidating” IMHO is that, in order to so some seemingly *simple* task such as adding members to a group, you basically need to edit the XML.
And when you don’t want to edit the XML but do it “programmatically”…. all it boils down to is STILL editing the XML and basically passing that XML into a method.
That’s what I love to call the XML tax… and I am not the only one thinking that, see what Jeff has to say about it http://www.codinghorror.com/blog/archives/001139.html
December 14th, 2008 at 8:51 pm
Edit XML… Not really as I see it… As I mention, as soon as you call get_InnerXml(), you output a string.
So realistically, you could just create that string from the beginning, and not get into doing XML.
I’m still planning to blog on this more soon…
December 30th, 2008 at 12:48 pm
[...] back to the quote above, everyone gets on the bandwagon posting examples and articles. I had been asked a few times about writing articles on OpsMgr and Powershell usage (for example by [...]