Powershell: Computer zwischen Collections verschieben

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