Introduction
This is the 5th instalment of the Automating OpsMgr series. Previously on this series:
- Automating OpsMgr Part 1: Introducing OpsMgrExtended PowerShell / SMA Module
- Automating OpsMgr Part 2: SMA Runbook for Creating ConfigMgr Log Collection Rules
- Automating OpsMgr Part 3: New Management Pack Runbook via SMA and Azure Automation
- Automating OpsMgr Part 4:Creating New Empty Groups
In the previous post (part 4), I have demonstrated a runbook creating new empty instance groups and computer groups using the OpsMgrExtended module. As I also mentioned in Part 4, I will dedicate few posts on creating and managing OpsMgr groups. So, this post is the 2nd one on this topic.
In OpsMgr, groups can be populated via Explicit memberships (static) or Dynamic Memberships (query based), or combination of both:
In this post, I will demonstrate how to use a runbook to add a Windows computer object to a computer group via Explicit membership.
Runbook Add-ComputerToComputerGroup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
Workflow Add-ComputerToComputerGroup { Param( [Parameter(Mandatory=$true)][String]$GroupName, [Parameter(Mandatory=$true)][String]$ComputerPrincipalName ) #Get OpsMgrSDK connection object $OpsMgrSDKConn = Get-AutomationConnection -Name "OpsMgrSDK_TYANG" $bComputerAdded = Inlinescript { #Connecting to the management group $MG = Connect-OMManagementGroup -SDKConnection $USING:OpsMgrSDKConn #Get the windows computer object Write-Verbose "Getting the Windows computer monitoring object for '$USING:ComputerPrincipalName'" $WinComputerObjectCriteria = New-Object Microsoft.EnterpriseManagement.Monitoring.MonitoringObjectGenericCriteria("FullName = 'Microsoft.Windows.Computer:$USING:ComputerPrincipalName'") $WinComputer = $MG.GetMonitoringObjects($WinComputerObjectCriteria)[0] If ($WinComputer -eq $null) { Write-Error "Unable to find the Microsoft.Windows.Computer object for '$USING:ComputerPrincipalName'." Return $false } $WinComputerID = $WinComputer.Id.ToString() Write-Verbose "Monitoring Object ID for '$USING:ComputerPrincipalName': '$WinComputerID'" #Get the group Write-Verbose "Getting the computer group '$USING:GroupName'." $ComputerGroupClassCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria("Name='$USING:GroupName'") $ComputerGroupClass = $MG.GetMonitoringClasses($ComputerGroupClassCriteria)[0] If ($ComputerGroupClass -eq $null) { Write-Error "$Using:GroupName is not found." Return $false } #Check if this monitoring class is actually a computer group Write-Verbose "Check if the group '$USING:GroupName' is a computer group" $ComputerGroupBaseTypes = $ComputerGroupClass.GetBaseTypes() $bIsComputerGroup = $false Foreach ($item in $ComputerGroupBaseTypes) { If ($item.Id.Tostring() -eq '0c363342-717b-5471-3aa5-9de3df073f2a') { $bIsComputerGroup = $true } } If ($bIsComputerGroup -eq $false) { Write-Error "$Using:GroupName is not a computer group" Return $false } #Get Group object $ComputerGroupObject = $MG.GetMonitoringObjects($ComputerGroupClass)[0] #Get Group population discovrey Write-Verbose "Getting the group discovery rule" $ComputerGroupDiscoveries = $ComputerGroupObject.GetMonitoringDiscoveries() $iGroupPopDiscoveryCount = 0 $GroupPopDiscovery = $null Foreach ($Discovery in $ComputerGroupDiscoveries) { $DiscoveryDS = $Discovery.DataSource #Microsft.SystemCenter.GroupPopulator ID is 488000ef-e20b-1ac4-d3b1-9d679435e1d7 If ($DiscoveryDS.TypeID.Id.ToString() -eq '488000ef-e20b-1ac4-d3b1-9d679435e1d7') { #This data source module is using Microsft.SystemCenter.GroupPopulator $iGroupPopDiscoveryCount = $iGroupPopDiscoveryCount + 1 $GroupPopDiscovery = $Discovery Write-Verbose "Group Populator discovery found: '$($GroupPopDiscovery.Name)'" } } If ($iGroupPopDiscoveryCount.count -eq 0) { Write-Error "No group populator discovery found for $Group." Return $false } If ($iGroupPopDiscoveryCount.count -gt 1) { Write-Error "$Group has multiple discoveries using Microsft.SystemCenter.GroupPopulator Module type." Return $false } #Get the MP of where the group populator discovery is defined $GroupPopDiscoveryMP = $GroupPopDiscovery.GetManagementPack() Write-Verbose "The group populator discovery '$($GroupPopDiscovery.Name)' is defined in management pack '$($GroupPopDiscoveryMP.Name)'." #Write Error and exit if the MP is sealed If ($GroupPopDiscoveryMP.sealed -eq $true) { Write-Error "Unable to update the group discovery because it is defined in a sealed MP: '$($GroupPopDiscoveryMP.DisplayName)'." Return $false } Write-Verbose "Updating the discovery data source configuration" $GroupDSConfig = $GroupPopDiscovery.Datasource.Configuration $GroupDSConfigXML = [XML]"<Configuration>$GroupDSConfig</Configuration>" #Detect if any MembershipRule segment contains existing static members $bComputerAdded = $false Foreach ($MembershipRule in $GroupDSConfigXML.Configuration.MembershipRules.MembershipRule) { If ($MembershipRule.IncludeList -ne $Null -and $bComputerAdded -eq $false) { #Add the monitoroing object ID of the Windows computer to the <IncludeList> node Write-Verbose "Adding '$USING:ComputerPrincipalName' monitoring Object ID '$WinComputerID' to the <IncludeList> node in the group populator configuration" $NewMOId = $MembershipRule.IncludeList.AppendChild($GroupDSConfigXML.CreateElement("MonitoringObjectId")) $NewMOId.InnerText = $WinComputerID $bComputerAdded = $true } } #If none of the MembershipRule has <IncludeList segment>, create it in the first MembershipRule If ($bComputerAdded -eq $false) { If ($GroupDSConfigXML.Configuration.MembershipRules.MembershipRule -Is [System.Array]) { Write-Verbose "Multiple Membership rules. creating <IncludeList> within the first <MembershipRule>" $IncludeListNode = $GroupDSConfigXML.Configuration.MembershipRules.MembershipRule[0].AppendChild($GroupDSConfigXML.CreateElement("IncludeList")) } else { Write-Verbose "There is only one Membership rule. creating <IncludeList> in it." $IncludeListNode = $GroupDSConfigXML.Configuration.MembershipRules.MembershipRule.AppendChild($GroupDSConfigXML.CreateElement("IncludeList")) } $NewMOId = $IncludeListNode.AppendChild($GroupDSConfigXML.CreateElement("MonitoringObjectId")) $NewMOId.InnerText = $WinComputerID } $UpdatedGroupPopConfig = $GroupDSConfigXML.Configuration.InnerXML #Updating the discovery Write-Verbose "Updating the group discovery" Try { $GroupPopDiscovery.Datasource.Configuration = $UpdatedGroupPopConfig $GroupPopDiscovery.Status = [Microsoft.EnterpriseManagement.Configuration.ManagementPackElementStatus]::PendingUpdate $GroupPopDiscoveryMP.AcceptChanges() $bComputerAdded = $true } Catch { $bComputerAdded = $false } $bComputerAdded } If ($bComputerAdded -eq $true) { Write-Output "Done." } else { throw "Unable to add '$ComputerPrincipalName' to group '$GroupName'." exit } } |
When using this runbook, you will need to update line 9 of the runbook, and replace the SMA connection name with the one you’ve used in your SMA environment:
This runbook requires 2 mandatory parameters:
- Windows computer principal name (FQDN) – which is the key property of the Windows Computer object
- The group name – it’s the internal name, not the display name. I did not use the display name because it is not unique. i.e.
Note:
If the group was created using the New-OMComputerGroup and New-OMInstanceGroup functions from the OpsMgrExtended module, these 2 functions would automatically prepend the management pack name in front of the group name specified by the user (if the management pack name is not already the prefix of the specified names). I forgot to mention this behaviour in my previous post (Part 4).
Since the OpsMgrExtended module does not (yet) have a function to add a computer to a computer group, I wrote this runbook to perform this task directly via OpsMgr SDK (therefore all within the inlinescript). The high level steps for this runbook is listed below:
- Establish OpsMgr management group connection (and the SDK assemblies will be loaded automatically).
- Get the Windows computer monitoring object
- Get the computer group monitoring class (singleton class)
- Check if the group object specified is indeed a computer group
- Get the computer group instance
- Get the computer group discovery
- Make sure the discovery is defined in an unsealed management pack
- Detect if any “MembershipRule” segments in discovery data source module contains existing static members
- If there are existing static members in one of the membership rule, add the Windows computer as a static member in the membership rule.
- If none of the membership rules contain static members, define a static member section (“<IncludeList>”) in the first Membership Rule.
- Update the unsealed management pack where the discovery is defined.
Executing Runbook
Group membership before execution:
Executing runbook:
Group membership after execution:
Conclusion
In this post, I have demonstrated how to use a runbook and OpsMgrExtended module to add a Windows computer object as a static member of a computer group.
I’ve also demonstrated even when an activity is not pre-defined in the OpsMgrExnteded module, we can still leverage OpsMgrExnteded module to perform the task because we can directly interact with OpsMgr management groups and SDKs via this module – by using the Connect-OMManagementGroup function, the SDK will be loaded automatically.
When I was writing this runbook few days ago, I have realised this is something I should have included in the OpsMgrExtended module because it could be very common and useful. Although I’ve published this as a rather complex runbook at this stage, I will probably included this as an additional function in the future release of OpsMgrExtended module.
I will demonstrate how to add a explicit member to an instance group in the Part 6 of this series.
Tao Yang, I want to add several computers in one computer group. How can I run your script from SCOM server? Specifically, I can not run workflow, but when using script as a function, which is called withing cycle, SCOM can not update group quickly (I want to add 158 servers in one group)