This is a continuation of a Data Center Automation series of posts that I have been working on with Anders Bengtsson. Here are the first seven posts in this series:

Creating Management Packs in SCOM 2012 with PowerShell
Creating Performance Collection Rules in SCOM 2012 with PowerShell
Creating Event Based Alerting Rules in SCOM 2012 with PowerShell
Enabling or Disabling Workflows in SCOM 2012 with PowerShell
Deleting Workflows in SCOM 2012 with PowerShell
Creating Groups in SCOM 2012 with PowerShell
Adding References to MPs in SCOM 2012 with PowerShell

*Update v2.0*

Fixed…

  • Group membership being modified but not updating during GroupCalc
  • When all GUIDs are removed from a group it will not save properly
  • When all Membership rules are removed from a group it will not save properly

Improved…

  • XML handling
  • Error handling
  • Script output
  • Reference handling

Added support for…

  • Computer groups
  • Multiple membership rules
  • New management packs
  • New groups
  • Excluded instances (if they are in the UI, then they’ll get added automatically to the any membership rules created by the script)

*Update v2.1*

Improved…

  • New group creation and error handling

As of this post this script is not included as an activity in the Operations Manager Admin Integration Pack but will be in the next version. This was a challenging script to write because group modification requires XML manipulation as there are no methods for managing this. I chose to only support explicit membership with this script because that is likely the most common automation need.

Each group discovery can have multiple membership rules which are really only visible by reviewing the XML of the management pack. This script modifies any of these rules, including rules added via the SCOM Console. If the appropriate membership rule does not exist at runtime, then it will be created and members added. If it does exist then it gets the current explicit members, adds any new members passed, and finally removes any members passed. It then replaces the new old list with the new list while keeping any other membership rules not created with this script intact.

Since the plan is to use this in an integration pack it requires that the instances passed to the script be in GUID format and these GUIDs are validated by the script before being added to the group. You can get the GUIDs by using a simple PowerShell command:

Get-SCOMClass –Name ‘Microsoft.Windows.Computer’ | Get-SCOMClassInstance | select name, id

If you notice after running this script that the new members show up in the console under “Explicit Members” but not when you select “View Group Members” then the UI may just not be up to date. Try the following PowerShell command:

(Get-SCOMGroup –DisplayName ‘My Test Group 1’).GetRelatedMonitoringObjects() | select name, path, id

Syntax:

.\ModifyGroupMembership.ps1 –ManagementServer ‘om01.contoso.com’ –ManagementPackID ‘custom.example.test’ –GroupID ‘custom.example.test.group.testgroup1’ –InstancesToAdd ‘8d5e843d-4d4a-3821-91d1-bc6434d6f9f1, aa390a79-b72a-bf58-412b-ebb94a139e06’ –InstancesToRemove ‘732ac45e-4e1a-9369-c9dd-e3b038537474’

Parameters:

Name Description
ManagementServer Name of MS to connect to
ManagementPackID ID of the MP you want to create or modify
GroupID ID of the group you want to create or modify
InstancesToAdd Optional: GUIDs of the instances you want to add to the group. You can pass multiple by separating each with a  comma.
InstancesToRemove Optional: GUIDs of the instances you want to remove from the group. You can pass multiple by separating each with a  comma.
1 Param( 2 [parameter(Mandatory=$true)] 3 $ManagementServer, 4 [parameter(Mandatory=$true)] 5 $ManagementPackID, 6 [parameter(Mandatory=$true)] 7 $GroupID, 8 $InstancesToAdd, 9 $InstancesToRemove 10 ) 11 12 Write-Host "Version 2.0" 13 Write-Host "ManagementServer: "$ManagementServer 14 Write-Host "ManagementPackID: "$ManagementPackID 15 Write-Host "GroupID: "$GroupID 16 Write-Host "InstancesToAdd: "$InstancesToAdd 17 Write-Host "InstancesToRemove: "$InstancesToRemove 18 19 function GetSCOMManagementGroup 20 { 21 param($ms) 22 try 23 { 24 $mg = New-Object Microsoft.EnterpriseManagement.ManagementGroup($ms) 25 } 26 catch 27 { 28 Write-Host "Failed to Connect to SDK, Exiting:"$ms -ForegroundColor Red 29 Write-Host $_.Exception.Message -ForegroundColor Yellow 30 exit 31 } 32 return $mg 33 } 34 35 function GetManagementPackToUpdate 36 { 37 param($mg, $mpID) 38 try 39 { 40 $mp = $mg.GetManagementPacks($mpID)[0] 41 $vIncrement = $mp.Version.ToString().Split('.') 42 $vIncrement[$vIncrement.Length - 1] = ([system.int32]::Parse($vIncrement[$vIncrement.Length - 1]) + 1).ToString() 43 $mp.Version = ([string]::Join(".", $vIncrement)) 44 } 45 catch 46 { 47 Write-Host "New MP:"$mpID 48 $mp = CreateManagementPack -mpID $mpID 49 $mg.ImportManagementPack($mp) 50 $mp = GetManagementPack -mg $mg -mpID $mpID 51 } 52 return $mp 53 } 54 55 function GetManagementPack 56 { 57 param ($mg, $mpID) 58 try 59 { 60 $mp = $mg.GetManagementPacks($mpID)[0] 61 } 62 catch 63 { 64 Write-Host "Management Pack Not Found, Exiting:"$mpID -ForegroundColor Red 65 Write-Host $_.Exception.Message -ForegroundColor Yellow 66 exit 67 } 68 return $mp 69 } 70 71 function CreateManagementPack 72 { 73 param($mpID) 74 $mpStore = New-Object Microsoft.EnterpriseManagement.Configuration.IO.ManagementPackFileStore 75 $mp = New-Object Microsoft.EnterpriseManagement.Configuration.ManagementPack($mpID, $mpID, (New-Object Version(1, 0, 0)), $mpStore) 76 return $mp 77 } 78 79 function GetReferenceAlias 80 { 81 param($mp, $mpID) 82 if ($mp.Name.ToUpper() -ne $mpID.ToUpper()) 83 { 84 $bFound = $false 85 foreach ($ref in $mp.References) 86 { 87 $s = ($ref.Value.ToString().Split("=")[1]).Split(",")[0] 88 if ($s.ToUpper() -eq $mpID.ToUpper()) 89 { 90 $bFound = $true 91 $alias = $ref.Key 92 } 93 } 94 if (!($bFound)) 95 { 96 Write-Host "MP Reference Not Found, Exiting:"$mpID 97 exit 98 } 99 } 100 101 return $alias 102 } 103 104 function ValidateReference 105 { 106 param($mg, $mp, $mpID) 107 if ($mp.Name.ToUpper() -ne $mpID.ToUpper()) 108 { 109 $bFound = $false 110 foreach ($ref in $mp.References) 111 { 112 $s = ($ref.Value.ToString().Split("=")[1]).Split(",")[0] 113 if ($s.ToUpper() -eq $mpID.ToUpper()) {$bFound = $true} 114 } 115 if (!($bFound)) 116 { 117 Write-Host "New Reference:"$mpID 118 $mp = CreateReference -mg $mg -mp $mp -mpID $mpID 119 } 120 } 121 return $mp 122 } 123 124 function ValidateReferencesFromInstances 125 { 126 param($mg, $mp, $ht) 127 128 $htClasses = @{} 129 foreach($instance in $ht.GetEnumerator()) 130 { 131 try {$htClasses.Add($instance.Value.ToString(),$instance.Value)} catch {} 132 } 133 134 foreach($instance in $htClasses.GetEnumerator()) 135 { 136 $classMP = GetClassMPFromMG -mg $mg -criteria ([string]::Format("Name = '{0}'", $instance.Value)) 137 $mp = ValidateReference -mg $mg -mp $mp -mpID $classMP.Name 138 } 139 140 return $mp 141 } 142 143 function CreateReference 144 { 145 param($mg, $mp, $mpID) 146 try 147 { 148 $newMP = $mg.GetManagementPacks($mpID)[0] 149 if (!($newMP.sealed)) 150 { 151 Write-Host "MP to reference is not sealed, cannot add reference to"$mpID -ForegroundColor Red 152 Write-Host "Exiting" -ForegroundColor Red 153 Write-Host $_.Exception.Message -ForegroundColor Yellow 154 exit 155 } 156 } 157 catch 158 { 159 Write-Host "Referenced MP Not Found in Management Group, Exiting:"$mpID -ForegroundColor Red 160 Write-Host $_.Exception.Message -ForegroundColor Yellow 161 exit 162 } 163 164 $alias = $mpID.Replace(".","") 165 $reference = New-Object Microsoft.EnterpriseManagement.Configuration.ManagementPackReference($newMP) 166 $mp.References.Add($alias, $reference) 167 return $mp 168 } 169 170 function XMLEncode 171 { 172 param([string]$s) 173 $s = $s.Replace("&", "&amp;") 174 $s = $s.Replace("<", "&lt;") 175 $s = $s.Replace(">", "&gt;") 176 $s = $s.Replace('"', "&quot;") 177 $s = $s.Replace("'", "&apos;") 178 return $s.ToString() 179 } 180 181 function ValidateMonitoringObjects 182 { 183 param($guids, $mg) 184 [hashtable]$ht = @{} 185 $guids = $guids.Split(",") 186 foreach ($guid in $guids) 187 { 188 $guid = $guid.Trim() 189 try 190 { 191 $mo = $mg.GetMonitoringObject($guid) 192 try {$ht.Add($guid, ($mo.FullName).Split(":")[0])} catch {} 193 } 194 catch 195 { 196 try {$ht.Add($guid, 'NOTFOUND')} catch {} 197 } 198 } 199 return $ht 200 } 201 202 function GetClassMPFromMG 203 { 204 param($mg, $criteria) 205 $searchCriteria = new-object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria($criteria) 206 $class = ($mg.GetMonitoringClasses($searchCriteria))[0] 207 $mp = $class.GetManagementPack() 208 return $mp 209 } 210 211 function GetRelationshipMPFromMG 212 { 213 param($mg, $criteria) 214 $searchCriteria = new-object Microsoft.EnterpriseManagement.Configuration.MonitoringRelationshipClassCriteria($criteria) 215 $relationship = ($mg.GetMonitoringRelationshipClasses($searchCriteria))[0] 216 $mp = $relationship.GetManagementPack() 217 return $mp 218 } 219 220 function GetMPElementClass 221 { 222 param($mg, $mp, $class) 223 224 $criteria = ([string]::Format("Name = '{0}'", $class)) 225 $refMP = GetClassMPFromMG -mg $mg -criteria $criteria 226 $alias = "" 227 if ($refMP.Name -ne $mp.Name) 228 { 229 $alias = (GetReferenceAlias -mp $mp -mpID $refMP.Name) + "!" 230 } 231 $mpElement = '$MPElement[Name="{0}{1}"]$' -f $alias, $class 232 233 return $mpElement 234 } 235 236 function GetMPElementRelationship 237 { 238 param($mg, $mp, $class, $relationship) 239 240 if (($relationship.ToString() -eq 'Microsoft.SystemCenter.ComputerGroupContainsComputer') -and ($class.ToString() -ne 'Microsoft.Windows.Computer')) 241 { 242 $mpName = 'System.Library' 243 $relationship = 'System.ConfigItemContainsConfigItem' 244 } 245 else 246 { 247 $criteria = ([string]::Format("Name = '{0}'", $relationship)) 248 $mpName = (GetRelationshipMPFromMG -mg $mg -criteria $criteria).Name 249 } 250 251 $alias = "" 252 if ($mpName -ne $mp.Name) 253 { 254 $alias = (GetReferenceAlias -mp $mp -mpID $mpName) + "!" 255 } 256 $mpElement = '$MPElement[Name="{0}{1}"]$' -f $alias, $relationship 257 258 return $mpElement 259 } 260 261 function GetGroup 262 { 263 param($mg, $mp, $groupID) 264 $group = $mg.GetMonitoringClasses($groupID)[0] 265 if ($group -eq $null) 266 { 267 Write-Host "Group Not Found:"$groupID -ForegroundColor Red 268 $newGroupID = $mp.Name + ($groupID.Split("."))[-1] 269 $group = $mg.GetMonitoringClasses($groupID)[0] 270 if ($group -eq $null) 271 { 272 Write-Host "Group Not Found, Exiting:"$newGroupID -ForegroundColor Red 273 exit 274 } 275 } 276 return $group 277 } 278 279 function ValidateGroup 280 { 281 param($mg, $mp, $groupID) 282 $group = $mg.GetMonitoringClasses($groupID)[0] 283 if ($group -eq $null) 284 { 285 $groupName = ($groupID.Split("."))[-1] 286 $groupID = $groupName 287 $newGroupID = $mp.Name + "." + $groupID 288 Write-Host "New Group:"$newGroupID 289 $mp = CreateGroup -mg $mg -mp $mp -groupID $groupID -groupName $groupName 290 } 291 return $mp 292 } 293 294 function CreateGroup 295 { 296 param($mg, $mp, $groupID, $groupName) 297 $mp = ValidateReference -mg $mg -mp $mp -mpID 'Microsoft.SystemCenter.InstanceGroup.Library' 298 $mp = ValidateReference -mg $mg -mp $mp -mpID 'System.Library' 299 $alias = GetReferenceAlias -mp $mp -mpID 'Microsoft.SystemCenter.InstanceGroup.Library' 300 $systemAlias = GetReferenceAlias -mp $mp -mpID 'System.Library' 301 $formula ='<MembershipRule Comment="Empty Membership Rule">' + ` 302 '<MonitoringClass>$MPElement[Name="' + $alias + ` 303 '!Microsoft.SystemCenter.InstanceGroup"]$</MonitoringClass>' + ` 304 '<RelationshipClass>$MPElement[Name="' + $alias + ` 305 '!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass>' + ` 306 '<Expression>' + ` 307 '<SimpleExpression>' + ` 308 '<ValueExpression>' + ` 309 '<Property>$MPElement[Name="' + $systemAlias + ` 310 '!System.Entity"]/DisplayName$' + ` 311 '</Property>' + ` 312 '</ValueExpression>' + ` 313 '<Operator>Equal</Operator>' + ` 314 '<ValueExpression>' + ` 315 '<Value>False</Value>' + ` 316 '</ValueExpression>' + ` 317 '</SimpleExpression>' + ` 318 '</Expression>' + ` 319 '</MembershipRule>' 320 321 $group = New-Object Microsoft.EnterpriseManagement.Monitoring.CustomMonitoringObjectGroup($mp.Name, $groupID, (XMLEncode -s $groupName), $formula) 322 $mp.InsertCustomMonitoringObjectGroup($group) 323 return $mp 324 } 325 326 function CreateEmptyMembershipRule 327 { 328 param($mg, $mp, $relationship, $rules) 329 330 if ($relationship -eq 'Microsoft.SystemCenter.InstanceGroupContainsEntities') 331 { 332 $class = 'Microsoft.SystemCenter.InstanceGroup' 333 } 334 else 335 { 336 $class = 'Microsoft.Windows.Computer' 337 } 338 339 $propertyName = '$MPElement[Name="{0}!System.Entity"]/DisplayName$' -f (GetReferenceAlias -mp $mp -mpID 'System.Library') 340 341 $rulesNode = $rules.SelectSingleNode("/Node1/MembershipRules") 342 $rule = $rules.CreateElement("MembershipRule") 343 [void]$rule.SetAttribute("Comment", "Scripted Membership Rule") 344 [void]$rulesNode.AppendChild($rule) 345 346 $mClass = $rules.CreateElement("MonitoringClass") 347 $mClass.InnerText = (GetMPElementClass -mg $mg -mp $mp -class $class) 348 [void]$rulesNode.MembershipRule.AppendChild($mClass) 349 350 $rClass = $rules.CreateElement("RelationshipClass") 351 $rClass.InnerText = (GetMPElementRelationship -mg $mg -mp $mp -class $class -relationship $relationship) 352 [void]$rulesNode.MembershipRule.AppendChild($rClass) 353 354 $expression = $rules.CreateElement("Expression") 355 [void]$rulesNode.MembershipRule.AppendChild($expression) 356 357 $eNode = $rules.SelectSingleNode("/Node1/MembershipRules/MembershipRule/Expression") 358 $simpleExpression = $rules.CreateElement("SimpleExpression") 359 [void]$eNode.AppendChild($simpleExpression) 360 361 $sNode = $rules.SelectSingleNode("/Node1/MembershipRules/MembershipRule/Expression/SimpleExpression") 362 $valueExpression = $rules.CreateElement("ValueExpression") 363 [void]$sNode.AppendChild($valueExpression) 364 365 $vNode = $rules.SelectSingleNode("/Node1/MembershipRules/MembershipRule/Expression/SimpleExpression/ValueExpression") 366 $property = $rules.CreateElement("Property") 367 $property.InnerText = $propertyName 368 [void]$vNode.AppendChild($property) 369 370 $operator = $rules.CreateElement("Operator") 371 $operator.InnerText = "Equal" 372 [void]$sNode.AppendChild($operator) 373 374 $valueExpression = $rules.CreateElement("ValueExpression") 375 [void]$sNode.AppendChild($valueExpression) 376 377 $vNode = $sNode.ChildNodes[2] 378 $value = $rules.CreateElement("Value") 379 $value.InnerText = "False" 380 [void]$vNode.AppendChild($value) 381 382 return $rules 383 } 384 385 function GetGroupDiscovery 386 { 387 param($group) 388 $groupDiscovery = $group.GetMonitoringDiscoveries()[0] 389 if ($groupDiscovery -eq $null) 390 { 391 Write-Host "Group Discovery Not Found, Exiting" -ForegroundColor Red 392 exit 393 } 394 return $groupDiscovery 395 } 396 397 function GetGroupMembershipRules 398 { 399 param($config) 400 $rulesStart = $config.IndexOf("<MembershipRules>") 401 $rulesEnd = ($config.IndexOf("</MembershipRules>") + 18) - $rulesStart 402 $rules = $config.Substring($rulesStart, $rulesEnd) 403 $rules = '<Node1>' + $rules + '</Node1>' 404 return $rules 405 } 406 407 function GetGroupInstances 408 { 409 param($mg, $mp, $groupID) 410 411 $group = GetGroup -mg $mg -mp $mp -groupID $groupID 412 $discovery = GetGroupDiscovery -group $group 413 $configuration = $discovery.DataSource.Configuration 414 $rules = GetGroupMembershipRules -config $configuration 415 $xPath = "/Node1/MembershipRules/MembershipRule/IncludeList/MonitoringObjectId" 416 $guids = Select-Xml -Content $rules -XPath $xPath 417 $existingInstances = @{} 418 419 foreach($instance in $guids) 420 { 421 try {$existingInstances.Add($instance.ToString(),$instance)} catch {} 422 } 423 424 return $existingInstances 425 } 426 427 function UpdateGroup 428 { 429 param($mg, $mp, $groupID, $instancesToAdd, $instancesToRemove) 430 431 $existingInstances = GetGroupInstances -mg $mg -mp $mp -groupID $groupID 432 433 if ($instancesToAdd -ne $null){$instancesToAdd = ValidateMonitoringObjects -guids $instancesToAdd -mg $mg} 434 else {$instancesToAdd = @{}} 435 436 $instancesToAdd = RemoveEntriesFromHashTable -guids $instancesToRemove -existingInstances $existingInstances -ht $instancesToAdd 437 $mp = ValidateReferencesFromInstances -mg $mg -mp $mp -ht $instancesToAdd 438 439 Write-Host "Update MP:"$mp.Name 440 $mp.AcceptChanges() 441 $mp = GetUpdatedGroupDiscovery -mg $mg -mp $mp -groupID $groupID -instancesToAdd $instancesToAdd -instancesToRemove $instancesToRemove 442 443 return $mp 444 } 445 446 function GetUpdatedGroupDiscovery 447 { 448 param($mg, $mp, $groupID, $instancesToAdd, $instancesToRemove) 449 $group = GetGroup -mg $mg -mp $mp -groupID $groupID 450 $discovery = GetGroupDiscovery -group $group 451 $configuration = $discovery.DataSource.Configuration 452 $relationship = GetRelationshipType -mg $mg -discovery $discovery 453 [xml]$rules = GetGroupMembershipRules -config $configuration 454 $exclusions = GetExclusions -rules $rules 455 456 foreach($instance in $instancesToAdd.GetEnumerator()) 457 { 458 $rules = AddGUIDToDiscovery -guid $instance.Key.ToString() -mg $mg -mp $mp -class $instance.Value.ToString() -rules $rules -exclusions $exclusions -relationship $relationship 459 } 460 461 if ($instancesToRemove -ne $null) 462 { 463 foreach($instance in $instancesToRemove.Split(",")) 464 { 465 Write-Host "Delete GUID:"$instance 466 $rules = RemoveGUIDFromDiscovery -guid $instance.Trim() -rules $rules 467 } 468 469 $rules = DeleteEmptyIncludeNodes -mg $mg -mp $mp -rules $rules -relationship $relationship 470 } 471 472 $configuration = CleanUpDiscoveryConfiguration -configuration $configuration -rules $rules 473 474 $discovery.Status = [Microsoft.EnterpriseManagement.Configuration.ManagementPackElementStatus]::PendingUpdate 475 $discovery.DataSource.Configuration = $configuration.ToString().Trim() 476 $mp = $discovery.GetManagementPack() 477 Write-Host "Update MP:"$mp.Name 478 [void]$mp.AcceptChanges() 479 [void]$mg.RefreshMonitoringGroupMembers($mp) 480 481 return $mp 482 } 483 484 function DeleteEmptyIncludeNodes 485 { 486 param($mg, $mp, $relationship, $rules) 487 $xPath = "/Node1/MembershipRules/MembershipRule" 488 $nodes = $rules.SelectNodes($xPath) 489 490 foreach ($node in $nodes) 491 { 492 if (($node.IncludeList.ChildNodes.Count -eq 0) -and ($node.IncludeList.MonitoringObjectId.Count -eq 0)) 493 { 494 if ((($node.SelectSingleNode("Expression")).Name -eq 'Expression') -and (($node.SelectSingleNode("IncludeList")).Name -eq 'IncludeList')) 495 { 496 [void]$node.RemoveChild($node.SelectSingleNode("IncludeList")) 497 } 498 elseif (($node.SelectSingleNode("IncludeList")).Name -eq 'IncludeList') 499 { 500 [void]$node.ParentNode.RemoveChild($node) 501 } 502 } 503 } 504 505 if ($rules.SelectNodes($xPath).Count -eq 0) 506 { 507 $rules = CreateEmptyMembershipRule -mg $mg -mp $mp -relationship $relationship -rules $rules 508 } 509 510 return $rules 511 } 512 513 function CleanUpDiscoveryConfiguration 514 { 515 param($configuration, $rules) 516 517 $newRules = ($rules.OuterXml).Replace("<Node1>", "").Replace("</Node1>", "") 518 $i = $configuration.IndexOf("<MembershipRules>") 519 [string]$configuration = $configuration.SubString(0, $i) + $newRules 520 521 return $configuration 522 } 523 524 function GetRelationshipType 525 { 526 param($mg, $discovery) 527 $id = ($discovery.DiscoveryRelationshipCollection[0].TypeID).ToString().Split("=")[1] 528 $criteria = ([string]::Format("Id = '{0}'", $id)) 529 $searchCriteria = new-object Microsoft.EnterpriseManagement.Configuration.MonitoringRelationshipClassCriteria($criteria) 530 $relationship = ($mg.GetMonitoringRelationshipClasses($searchCriteria))[0] 531 return $relationship 532 } 533 534 function GetExclusions 535 { 536 param($rules) 537 $xPath = "/Node1/MembershipRules/MembershipRule/ExcludeList/MonitoringObjectId" 538 $guids = $rules.SelectNodes($xPath) 539 $exclusions = @{} 540 541 foreach($instance in $guids) 542 { 543 try {$exclusions.Add($instance.InnerText.ToString(),$instance.InnerText.ToString())} catch {} 544 } 545 546 return $exclusions 547 } 548 549 function AddGUIDToDiscovery 550 { 551 param($mg, $mp, $guid, $class, $rules, $exclusions, $relationship) 552 553 $guids = GetIncludedGUIDS -rules $rules 554 555 if (!($guids.Contains($guid))) 556 { 557 $classes = GetMembershipRuleMonitoringClasses -rules $rules 558 Write-Host "New GUID:"$guid":"$class 559 if ($classes.ContainsKey($class.ToString())) 560 { 561 $rules = AddIncludeGUID -rules $rules -guid $guid -class $classes.Get_Item($class.ToString()) 562 } 563 else 564 { 565 Write-Host "New Membership Rule:"$class 566 $rules = CreateNewMembershipRule -mg $mg -mp $mp -rules $rules -guid $guid -class $class -exclusions $exclusions -relationship $relationship 567 } 568 } 569 570 return $rules 571 } 572 573 function CreateNewMembershipRule 574 { 575 param($mg, $mp, $guid, $class, $rules, $exclusions, $relationship) 576 577 [xml]$xml = $rules 578 579 $rulesNode = $xml.SelectSingleNode("/Node1/MembershipRules") 580 $rule = $xml.CreateElement("MembershipRule") 581 [void]$rule.SetAttribute("Comment", "Scripted Membership Rule") 582 [void]$rulesNode.AppendChild($rule) 583 584 $mClass = $xml.CreateElement("MonitoringClass") 585 $mClass.InnerText = (GetMPElementClass -mg $mg -mp $mp -class $class) 586 [void]$rulesNode.MembershipRule.AppendChild($mClass) 587 588 $rClass = $xml.CreateElement("RelationshipClass") 589 $rClass.InnerText = (GetMPElementRelationship -mg $mg -mp $mp -class $class -relationship $relationship) 590 [void]$rulesNode.MembershipRule.AppendChild($rClass) 591 592 $iList = $xml.CreateElement("IncludeList") 593 [void]$rulesNode.MembershipRule.AppendChild($iList) 594 595 $count = ($rulesNode.ChildNodes.Count) - 1 596 $includeNode = $rulesNode.ChildNodes[$count].ChildNodes[2] 597 $mObjectId = $xml.CreateElement("MonitoringObjectId") 598 $mObjectId.InnerText = $guid.Trim() 599 [void]$includeNode.AppendChild($mObjectId) 600 601 if ($exclusions.Count -gt 0) 602 { 603 $eList = $xml.CreateElement("ExcludeList") 604 [void]$rulesNode.MembershipRule.AppendChild($eList) 605 606 foreach ($guid in $exclusions.GetEnumerator()) 607 { 608 $excludeNode = $rulesNode.ChildNodes[$count].ChildNodes[3] 609 $mObjectId = $xml.CreateElement("MonitoringObjectId") 610 $mObjectId.InnerText = $guid.Value.ToString().Trim() 611 [void]$excludeNode.AppendChild($mObjectId) 612 } 613 } 614 615 return $xml 616 } 617 618 function AddIncludeGUID 619 { 620 param($guid, $class, $rules) 621 622 [xml]$xml = $rules 623 $xPath = "/Node1/MembershipRules/MembershipRule" 624 $ruleNodes = $xml.SelectNodes($xPath) 625 626 foreach ($rule in $ruleNodes) 627 { 628 $className = ($rule.Get_InnerXML()).Split('"')[1] 629 if ($className -eq $class) 630 { 631 $includeNode = $rule.SelectSingleNode("IncludeList") 632 if ($includeNode -ne $null) 633 { 634 $child = $xml.CreateElement("MonitoringObjectId") 635 $child.InnerText = $guid 636 [void]$includeNode.AppendChild($child) 637 break 638 } 639 } 640 } 641 642 return $xml 643 } 644 645 function GetMembershipRuleMonitoringClasses 646 { 647 param($rules) 648 649 [xml]$xml = $rules 650 $xPath = "/Node1/MembershipRules/MembershipRule" 651 $ruleNodes = $xml.SelectNodes($xPath) 652 $ht = @{} 653 654 foreach ($rule in $ruleNodes) 655 { 656 $includeNode = $rule.SelectSingleNode("IncludeList") 657 if ($includeNode -ne $null) 658 { 659 $fullPath = ($rule.Get_InnerXML()).Split('"')[1] 660 $class = $fullPath.Split("!")[1] 661 try { $ht.Add($class.ToString(), $fullPath) } catch {} 662 } 663 } 664 665 return $ht 666 } 667 668 function GetIncludedGUIDs 669 { 670 param($rules) 671 $xPath = "/Node1/MembershipRules/MembershipRule/IncludeList/MonitoringObjectId" 672 $guids = $guids = $rules.SelectNodes($xPath) 673 $ht = @{} 674 foreach ($g in $guids) { try { $ht.Add($g.InnerText.ToString(), $g.InnerText.ToString()) } catch {} } 675 return $ht 676 } 677 678 function RemoveGUIDFromDiscovery 679 { 680 param($guid, $rules) 681 $xPath = "/Node1/MembershipRules/MembershipRule/IncludeList[MonitoringObjectId='{0}']/MonitoringObjectId" -f $guid.ToString() 682 $guids = $rules.SelectNodes($xPath) 683 684 foreach ($g in $guids) 685 { 686 if ($g.InnerText -eq $guid.ToString()) 687 { 688 [void]$g.ParentNode.RemoveChild($g) 689 } 690 } 691 692 return $rules 693 } 694 695 function RemoveEntriesFromHashTable 696 { 697 param($guids, $existingInstances, $ht) 698 if ($guids -ne $null) 699 { 700 $guids = $guids.Split(",") 701 foreach ($guid in $guids) 702 { 703 $guid = $guid.Trim() 704 try 705 { 706 $ht.Remove($guid) 707 } 708 catch {} 709 } 710 } 711 712 foreach ($guid in $existingInstances.GetEnumerator()) 713 { 714 if ($ht.ContainsKey($guid.Key.ToString())) 715 { 716 $ht.Remove($guid.Key.ToString()) 717 } 718 } 719 return $ht 720 } 721 722 try { Import-Module OperationsManager } catch 723 { 724 Write-Host "SCOM Module Not Found, Exiting" -ForegroundColor Red 725 Write-Host $_.Exception.Message -ForegroundColor Yellow 726 exit 727 } 728 729 $MG = GetSCOMManagementGroup -ms $ManagementServer 730 $MP = GetManagementPackToUpdate -mg $MG -mpID $ManagementPackID 731 $MP = ValidateGroup -mg $MG -mp $MP -groupID $GroupID 732 $MP = UpdateGroup -mg $MG -mp $MP -groupID $GroupID -instancesToAdd $InstancesToAdd -instancesToRemove $InstancesToRemove 733 734 Write-Host "Script Complete"