Ihr habt sicher auch schon (mehr als) einmal vor der Anforderung gestanden, Computerkonten in oder aus einer Sammlung aufzunehmen bzw. zu entfernen. Bei einzelnen Computerkonten ist das sicherlich einfach über die ConfigMgr Console zu lösen, doch sind mehrere Computerkonten betroffen, kann es doch recht aufwendig werden!
Vor kurzem bekam ich eine Anforderung, bei der ich wieder vor einer ähnlichen Problemstellung stand und habe zur Powershell gegriffen. Was dabei heraus gekommen ist, möchte ich euch mit diesem Artikel gerne näher erläutern.
Die Grundlagen
Bevor wir uns den eigentlichen Scripts widmen, noch ein paar Grundlagen:
Collection Memberships
Die Inhalte einer Collection, werden über sogenannte Collection Memberships definiert. Dabei werden nicht die Resources selbst, sondern Collection Membership Rules hinzugefügt bzw. entfernt.
Aus der ConfigMgr Console kennt ihr sicher die verschiedenen Varianten:
Variante | Beschreibung |
---|---|
Direct Membership | Eine “direkte Mitgliedschaft”, bezogen auf genau eine Resource, die über den Namen – eindeutig – gefiltert wird. |
Query Based Membership | In diesem Fall werden die Mitglieder über eine Abfrage (WQL) bestimmt. Alle Ergebnisse werden als Mitglieder übernommen. |
Include Collection Membership | Bei dieser Variante wird eine weitere Collection und damit deren Inhalt, vollständig übernommen. Verändert sich der Inhalt der verknüpften Liste, nimmt dies auch Auswirkung auf die betroffene Collection. Diese Variante kann auch als white listening verstanden werden. |
Exclude Collection Membership | Diese Art ist vergleichbar mit der Include Collection Membership, mit einem Unterschied: Alle Resources der verknüpften Collection, wird aus der betroffenen Collection ausgeschlossen. Auch in diesem Fall beeinträchtigen Änderungen an der “exkludierten” Collection, den Inhalt der betroffenen Collection. Diese Variante kann als eine Art: black listening gesehen werden. |
In unserem Fall nutzen wir die Direct Membership Rule um einzelne Geräte in eine Collection aufzunehmen bzw. aus dieser zu entfernen.
WMI Klassen
- SMS_Collection
-
SMS_CollectionRuleDirect
Die WMI Klasse SMS_CollectionRuleDirect entspricht einem Collection Membership Rule Eintrag. Wenn wir später die Collection Mitgliedschaften programmatisch bearbeiten, nutzen wir die Instanz dieser Klasse, um den gewünschten Eintrag aus der Collection zu entfernen bzw. einen neuen hinzuzufügen.
- SMS_R_System
Eine Instanz dieser Klasse entspricht den Computer- bzw. Geräteinformationen (System Resource).
Die Lösung
Wie üblich, habe ich zur Lösung wieder auf Powershell zurückgegriffen. In diesem Fall habe ich die ConfigMgr Powershell Cmdlets nicht genutzt, sondern bin direkt über die WMI Schnittstelle gegangen. Aber keine Sorge, alles auf Basis des offiziellen ConfigMgr SDK.
Wie bereits angesprochen, werden die Mitgliedschaften über die Collection Membership Rules definiert. Zum Hinzufügen oder Entfernen, werden nicht die Resources direkt, sondern die entsprechenden Rules bearbeitet.
Bevor wir in die Umsetzung gehen, schauen wir uns kurz noch an, wie wir diese Regel erstellen bzw. verwenden.
Die SMS_CollectionRuleDirect-Instanz
Im ersten Schritt, erstellen wir uns eine neue (leere) Instanz der Klasse SMS_CollectionRuleDirect, um eine direkte Zuordnung einer bestimmten Resource zu verändern. Danach legen wir durch setzen der Eigenschaften fest, welche Resource und Collection wir verändern wollen.
Werfen wir einen Blick auf die Eigenschaften, die wir setzen wollen:
Eigenschaft | Beschreibung/ Wert |
---|---|
ResourceClassName | Dieser Wert gibt an, für welche (Ziel)Ressource die Regel gilt. Mögliche Werte sind SMS_R_SYSTEM für Geräte- oder SMS_R_USER für Benutzer-Ressourcen. |
ResourceID | Über die ResourceID wird das gewünschte Geräte- oder Benutzerobjekt (SMS_R_Systen, SMS_R_User) ausgewählt, welches über die Regel in die Collection aufgenommen werden soll. |
RuleName | Dieser Wert setzt den Namen der Regel. Bei einer direkten Regel (SMS_CollectionRuleDirect) wird hier der Ressourcenname verwendet. |
Ein Beispiel:
# Get SMS_R_System by Name
$resource = Get-WmiObject -Class SMS_R_System -Filter "Name = 'TGC-DEV-001'" -ComputerName $SiteServer -Namespace $Namespace
Output:
Name ResourceID
---- ----------
TGC-DEV-001 16777219
Demnach würde dann die Regel mit den folgenden Werten erstellt werden:
# Get SMS_CollectionMembershipRule instance
$rule = ([WMIClass]"\\$SiteServer\root\sms\site_$($siteCode):SMS_CollectionRuleDirect").CreateInstance();
# Set rule properties
$rule.ResourceClassName = "SMS_R_System";
$rule.ResourceID = $resource.ResourceID; # 16777219
$rule.Rulename = $resource.Name; # TGC-DEV-001
Das Powershell Script
Endlich! Kommen wir zur Umsetzung. Nochmal zur Erinnerung: “Wir wollen eine (System)Ressource, von einer Collection, in die andere verschieben.”
Ausgangssituation
Objekt | WMI Class | Instance Name |
---|---|---|
Endgerät | SMS_R_System | TGC-DEV-001 |
Quellsammlung | SMS_Collection | Microsoft Quality Updates 2019.04 |
Zielsammlung | SMS_Collection | Microsoft Quality Updates 2019.05 |
1. Get-WmiObject -Class SMS_Collection
Im ersten Schritt lesen wir die Quellsammlung (SMS_Collection) aus dem ConfigMgr. Damit erhalten wir die Quelle, aus der wir das Endgerät entfernen:
# 1. Get SMS_Collection (Source)..
$collection = Get-WmiObject -Query "SELECT * FROM SMS_Collection WHERE Name='Microsoft Quality Updates 2019.04'" -ComputerName $SiteServer -Namespace $namespace
2. Get-WmiObject -Class SMS_R_System
Im nächsten Schritt suchen wir uns das Endgerät bzw. die System Resource heraus. Damit erhalten wir den ComputerName und ResourceID, welches wir für das erstellen der SMS_CollectionDirectRule benötigen.
# 2. Get SMS_R_System
$resource = Get-WmiObject -Query "SELECT * FROM SMS_R_System WHERE Name='TGC-DEV-001'" -ComputerName $SiteServer -Namespace $namespace
3. SMS_CollectionMembershipDirectRule
Jetzt erstellen wir noch eine neue Instanz der Klasse SMS_CollectionMembershipDirectRule und setzen die Eigenschaften des Endgerätes (s. Schritt 2. Get-WmiObject -Class SMS_R_System):
# 3. Create SMS_CollectionRuleDirect Instance
$rule = ([WMIClass]"\\$SiteServer\root\sms\site_$($siteCode):SMS_CollectionRuleDirect").CreateInstance();
# 3.1 Set rule properties
$rule.ResourceClassName = "SMS_R_System";
$rule.ResourceID = $resource.ResourceID;
$rule.Rulename = $resource.Name;
4. DeleteMembershipRule
Mit den Informationen der Collection und der MembershipRule, können wir den den ersten Teil des “Verschiebens” durchführen: Das Entfernen des Endgerätes aus der Quellsammlung.
Hierfür bietet die Instanz der Klasse SMS_Collection eine Methode an: DeleteMembershipRule. Dieser Methode übergeben wir unsere neue SMS_CollectionMembershipDirectRule. Als Rückgabe erhalten wir eine ResultObject, welches einen ErrorCode beinhaltet. (0 = Success).
# 4.2.2 Delete rule from memberships.
$resultObject = $collection.DeleteMembershipRule($rule);
# ReturnValue = 0 means: success.
$errorCode = $resultObject.ReturnValue;
5. AddMembershipRule
Nachdem wir erfolgreich das Endgerät aus der Quellsammlung entfernt haben, können wir dieses jetzt in die Zielsammlung aufnehmen. Dazu lesen wir (wieder) die Collection aus dem ConfigMgr aus. Nur dieses Mal suchen wir nach der Zielsammlung:
# 5. Get SMS_Collection (Target)..
$targetCollection = Get-WmiObject -Query "SELECT * FROM SMS_Collection WHERE Name='Microsoft Quality Updates 2019.05'" -ComputerName $SiteServer -Namespace $namespace
Die SMS_Collection bietet eine weitere Methode, die wir zur Aufnahme einer neuen Regel nutzen können: AddMembershipRule, die ebenfalls als Parameter eine Instanz der Klasse SMS_CollectionMembershipRule annimmt. Wir können die gleiche Instanz nehmen, die wir auch für das Entfernen aus der Quellsammlung genutzt haben:
# 6. Add rule to collection members.
$resultObject = $targetCollection.AddMembershipRule($rule);
# ReturnValue = 0 means: success.
$errorCode = $resultObject.ReturnValue;
Finally ..
Congratulations! Damit haben wir erfolgreich ein Endgerät, zwischen zwei Collections verschoben.
Anmerkungen
Bevor eine MembershipRule entfernt oder hinzugefügt wird, empfehle ich euch vorher zu prüfen, ob diese Regel (bereits) existiert. Dadurch vermeidet ihr eine Exception beim Ausführen der Methoden. Leider liefern keine expliziten ErrorCode für den Status “Exists” bzw. “NotExists”.
Die Prüfung ist recht simple und durch eine weitere WMI Abfrage zu lösen. Bspw. so:
# 4.2.1 Resource is a member?
$memberExists = Get-WmiObject -Class SMS_FullCollectionMembership -ComputerName $SiteServer -Namespace $namespace | Where-Object { ($_.CollectionID -eq $collection.CollectionID) -and ($_.ResourceID -eq $resource.ResourceID) }
Falls bereits eine Regel existiert, bekommt ihr als Rückgabe dieser Abfrage die passende SMS_CollectionMembershipRule, die ihr sonst auch manuell gebaut hättet.
Keep PoSh-ing IT!
/Ben