Skip to main content

Converting Configuration Manager Direct Membership Collections

· loading ·
Microsoft Configuration Manager Windows 10 and later Collections PowerShell
Author
Nick Benton
Principal Cloud Endpoint Consultant and Intune Blogger
Table of Contents

You may be using Direct Membership Rules in your Microsoft Configuration Manager environment, but should you really for critical production collections?

No is the answer, there I said it. Mainly because they require actual effort and overhead to maintain, and secondly because there have been times where these memberships just plain disappear, for many different reasons, but primarily if the ConfigMgr Client is reinstalled on the device.

So what do we do? <spoiler> Aggressive PowerShell scripts obviously. </spoiler>

The Approach
#

We’ll need to connect to the Configuration Manager PowerShell module, which is easy enough from the Primary Site server, then carry out the following actions:

  • Get the Device Collections with Direct Members
  • Capture the Direct Members
  • Create a new Query Membership Rule with the members
  • Remove the existing Direct Members
  • Logging?

So let’s get at it…

Connecting via PowerShell
#

From the Configuration Manager server we can leverage the PowerShell Module, import it and then connect to the PSDrive where we get to run all the Configuration Manager commands

Import-module ($Env:SMS_ADMIN_UI_PATH.Substring(0, $Env:SMS_ADMIN_UI_PATH.Length - 5) + '\ConfigurationManager.psd1')
$SiteCode = Get-PSDrive -PSProvider CMSITE
Set-location $SiteCode":"

Getting the Collections
#

I thought I’d be kind and give a couple of options to the Collection gathering, attack all of the Device Collections or, which is probably more sensible, bring up a list of collections to work with.

We’re doing this through a selection option at the start of the script and using Get-CMDeviceCollection:

if ($Choice_Number -eq '1') {
    Write-Host "Getting Device Collections with Direct Membership Rules..." -ForegroundColor Yellow
    $Collections = @(Get-CMDeviceCollection | Where-Object { $_.CollectionRules -like '*SMS_CollectionRuleDirect*' } | Select-Object Name, CollectionID, CollectionRules | Out-GridView -PassThru -Title 'Wait for all Collections to load, then select the Device Collections you want to convert. Use The ENTER Key or Mouse \ OK Button.')
}
if ($Choice_Number -eq '2') {
    Write-Host "Getting Device Collections with Direct Membership Rules..." -ForegroundColor Yellow
    $Collections = Get-CMDeviceCollection | Where-Object { $_.CollectionRules -like '*SMS_CollectionRuleDirect*' } | Select-Object Name, CollectionID, CollectionRules
}

We need to now identify whether these collection have Direct Members, so for each collection we can look at the CollectionRules attribute, and see if it contains SMS_CollectionRuleDirect:

foreach ($Collection in $Collections) {
    if ($Collection.CollectionRules -like "*SMS_CollectionRuleDirect*") {
    }
}

Now we know this collection has Direct Members, let’s get them using Get-CMDeviceCollectionDirectMembershipRule:

$DirectMembers = Get-CMDeviceCollectionDirectMembershipRule -CollectionName $Collection.Name

Cool, easy part done.

Building the Query
#

An easy replacement for the Direct Membership Rule is to use a List of Values Query based on System Name, so we’re going to use that, we’re going to use this as our basis for the new query once we’ve captured the Direct Members in a suitable format.

CCM Client Computer Name
#

select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_SYSTEM on SMS_G_System_SYSTEM.ResourceId = SMS_R_System.ResourceId where SMS_G_System_SYSTEM.Name in ("COMPUTER1", "COMPUTER2")

AD Client Computer Name
#

select SMS_R_System.ResourceId, SMS_R_System.ResourceType, SMS_R_System.Name, SMS_R_System.SMSUniqueIdentifier, SMS_R_System.ResourceDomainORWorkgroup, SMS_R_System.Client from  SMS_R_System where SMS_R_System.Name in ("COMPUTER1", "COMPUTER2")

We also need to get the names of the Direct Members, throw them into an Array as part of the foreach loop, then squish the Array to a String and combine the template query and the members:

$RuleName = "Direct Membership Replacement Query"
$QueryPart = "select SMS_R_System.ResourceId, SMS_R_System.ResourceType, SMS_R_System.Name, SMS_R_System.SMSUniqueIdentifier, SMS_R_System.ResourceDomainORWorkgroup, SMS_R_System.Client from  SMS_R_System where SMS_R_System.Name in ("

if ($Collection.CollectionRules -like "*SMS_CollectionRuleDirect*") {
    $DirectMembers = Get-CMDeviceCollectionDirectMembershipRule -CollectionName $Collection.Name
    $MembersArray = @()
    foreach ($DirectMember in $DirectMembers) {
        $MembersArray += $DirectMember.RuleName
    }
    $Members = '"{0}"' -f ($MembersArray -join '","')
    $QueryExpression = $QueryPart + $Members + ")"
}

This gives us the complete query string which we can use later on to create the Query Membership Rule.

Updating the Rules
#

Using Add-CMDeviceCollectionQueryMembershipRule we can create the new rule in the Collection using the variables we created earlier:

Add-CMDeviceCollectionQueryMembershipRule -CollectionName $Collection.Name -QueryExpression $QueryExpression -RuleName $RuleName

And after successfully creating the rule we can use Remove-CMDeviceCollectionDirectMembershipRule to loop through the existing Direct Members and remove them:

foreach ($DirectMember in $DirectMembers) {
    Try {
        Remove-CMDeviceCollectionDirectMembershipRule -CollectionName $Collection.Name -ResourceID $DirectMember.ResourceID -Force
        }
    Catch {

    }
}

Running the Script
#

Now we have all the bits we needed in place (cough logging cough), we can launch the script and use the option to select a Collection first as a test before we run it across the entire environment.

Let’s run it on a test collection we know has direct members:

Device Collection

Run the script from an Elevated PowerShell prompt on your Primary Site Server:

Set-CollectionDirectToQueryMembership.ps1

Oh the Choices
#

Doing so will prompt you with options, oooo exciting, here we’ll select option 1:

Script Options

Doing so will open a grid view of the collections in your Configuration Manager environment, this may take a while to load, and you should wait for them to load before selecting and confirming your Collections:

PowerShell Grid

Search for the Collection you want to update and select ‘OK’:

PowerShell Selection

Converting the Rules
#

Now the magic happens, including a nice little output table of the results of the conversion:

Script Output

The Results Speak for Themselves
#

Now the script has completed, we can go and check on the results on the Device Collection itself, look no Direct Members any more:

Collection Results

With the new Query in place:

Collection Query

Summary
#

With this small but powerful script, you can remove all Direct Membership rules and use the more sustainable (and less likely to cause you problems), Query Rule on either Collections you know have Direct Members, or if you’re feeling brave, your entire set of Device Collections.

This saves you having to manually create the Rules, or even the collections, which would mean re-deploying configuration, updates, applications etc. to a new Collection.

What a time saver.

Related

Retrofitting Windows Autopilot Group Tags
· loading
Microsoft Intune Windows 10 and later Windows Autopilot Enrolment Graph API PowerShell
Configuring Dell BIOS Settings with Microsoft Intune
· loading
Microsoft Intune Windows 10 and later Dell Apps BIOS Hardware PowerShell
Windows Operating System Compliance Updates
· loading
Microsoft Intune Windows 10 and later Compliance Updates Security Graph API PowerShell