What is Boundary Group Caching
Boundary group caching was introduced with the first version of System Center Configuration Manager (ConfigMgr) Current Branch (CB): version 1511. As the term implies, clients cache the name of their current boundary groups. They are then able to send this cached boundary group name to the management point during content location requests.
By caching the boundary group and sending it along with each content location request, the management point no longer needs to look up a client’s boundary or boundary group for each and every content location request. This dramatically reduces the additional load on management points and the site’s SQL Server instance caused by these repetitive, redundant lookups.
When Do Clients Cache Their Boundary Group
Similar to management point assignment, client’s refresh their current boundary group at three “times”:
- Every 25 hours
- At client agent startup
- When a network change is detected
Where Do Clients Cache Their Boundary Group
As with most things in ConfigMgr and on a ConfigMgr managed system, in particular, the answer is in WMI. Specifically, in the root\ccm\LocationServices namespace in a BoundaryGroupCache class object. This class contains two attributes:
- BoundaryGroupIDs — An array of IDs corresponding to the IDs of the boundary groups that the client is a member of.
- CacheToken — The time the cache was refreshed last.
The following screenshot is from WMI Explorer on one of my lab clients and shows the content of an instance of this class. If the client does not fall within the scope of any boundary groups, then the BoundaryGroupIDs attribute will not exist in the instance of the class.
[ms_panel title=”Note” title_color=”#00274c” border_color=”#00274c” title_background_color=”#f5f5f5″ border_radius=”2″ class=”” id=””]As of CB 1610, all clients that do not fall within the scope of a defined boundary group will be associated with the Default Boundary Group. This is not reflected in the BoundaryGroupCache class. Essentially, if the instance of the BoundaryGroupCache class contains no BoundaryGroupIDs, then the client is considered within the scope of the Default Boundary Group.[/ms_panel]
The Boundary Group IDs aren’t shown directly in the ConfigMgr console; however, you can quickly get them in PowerShell, via WMI (from the site’s SMS Provider), or SQL. With PowerShell, connect to your site and use the Get-CMBoundaryGroup cmdlet.
In SQL, merely query the vSMS_BoundaryGroup view.
[ms_panel title=”Note” title_color=”#00274c” border_color=”#00274c” title_background_color=”#f5f5f5″ border_radius=”2″ class=”” id=””]I can find no evidence of boundary caching activity in any standard client logs so if you need to check the values or when the boundary group was cached, check WMI.[/ms_panel]
WMI You Say
Yes, WMI. That means that we can add this class to hardware inventory to collect the information from the clients periodically.
Missing Boundaries
Once ConfigMgr collects the Boundary Group Cache information using hardware inventory, you’ll be able to easily identify clients that do not fall within the scope of a defined boundary group. To do this, create a new Query in the ConfigMgr console with the following specified on the General tab:
Class | Attribute |
System Resource | NetBIOS Name |
BoundaryGroupCache | BoundaryGroupIDs |
[ms_panel title=”Note” title_color=”#00274c” border_color=”#00274c” title_background_color=”#f5f5f5″ border_radius=”2″ class=”” id=””]Always use the NetBIOS Name attribute in your queries when you want to show the name of a system from the System Resource class as this attribute is backed by an indexed column in the SQL Server database.[/ms_panel]
Alternatively, you can use the following WQL in your query:
[code title="Boundary Group Query" lang="tsql"]select SMS_R_System.NetbiosName , SMS_G_System_BOUNDARYGROUPCACHE.BoundaryGroupIDs from SMS_R_System inner join SMS_G_System_BOUNDARYGROUPCACHE on SMS_G_System_BOUNDARYGROUPCACHE.ResourceId = SMS_R_System.ResourceId[/code]
In my lab, running this query results in an easy view of which clients do not fall within a defined boundary group (hint: it’s Win301 because the second column is blank for it).
You can, of course, modify, incorporate, improve, etc. this query as you see fit to give you exactly the results that you need. You can even translate it into a SQL query or report. Here’s a SQL statement to start with (note that this requires SQL Server 2016 and the database to be set at compatibility level 130 for the STRING_SPLIT function):
[code title="Boundary Group Query" lang="tsql"]SELECT rsys.Netbios_Name0 As Name , (SELECT bg.Name FROM vSMS_BoundaryGroup bg WHERE bg.GroupID = value) As 'Boundary Group' FROM v_R_System rsys INNER JOIN v_GS_BOUNDARYGROUPCACHE bgc ON bgc.ResourceID = rsys.ResourceID OUTER APPLY STRING_SPLIT(bgc.BoundaryGroupIDs0, ',')[/code]
Not being within the scope of a boundary group means one of two things — both of which are probably problematic and should be addressed:
- The client is not within the scope of any boundary.
- The client is within the scope of a boundary, but that boundary is not included in any boundary groups.
Either way, the client will automatically and immediately fallback to the Default Boundary Group and the site systems associated with it. This is probably not the desired result. If not, the next step is to lookup the IP Address of the client and see if it falls within a defined boundary. If not, it’s time to adjust your boundaries or create a new one. If it does fall within a defined boundary, then it’s time to figure out why that boundary is not included in a boundary group and either include it in an existing boundary group or create a new one.
Mad skills, Jason. This is very helpful to me in my site evaluations. Thanks.
Glad that you liked it!
Great article. I also added the IP Address column to the query so I can spot any ranges I might be missing.
Awesome. Blog it 🙂
Please do share Mike how you added the IP column to the query to spot any ranges missing
Which query are you referring to?
Here is the ConfigMgr query which also shows the IP address and the AD site name.
select SMS_R_System.NetbiosName, SMS_G_System_BOUNDARYGROUPCACHE.BoundaryGroupIDs, SMS_R_System.ADSiteName, SMS_R_System.IPAddresses from SMS_R_System inner join SMS_G_System_BOUNDARYGROUPCACHE on SMS_G_System_BOUNDARYGROUPCACHE.ResourceID = SMS_R_System.ResourceId
Hey Jason, Hope you’re doing well. Sharing with you my query that, looks to me to be super inefficient, but it runs against 40k records in 4 seconds and appears to give me the results i need without having to modify the SQL Compatibility level, which can cause some other issues with SCCM if you change from 110 to get that fancy split_string function.
Here it is – I would be curious to know how this works for others:
select count(distinct resourceid) [#SystemsPerBoundaryGroup], bg.name
from vsms_boundarygroup bg
left join (
select bgn.name, bgc.BoundaryGroupIDs0, bgn.groupid, bgc.resourceid from v_gs_boundarygroupcache bgc
join (select groupid, name from vsms_boundarygroup) bgn on bgc.BoundaryGroupIDs0 like ‘%’ + cast(bgn.groupid as varchar(max)) + ‘%’
) BoundariesSplitUp on bg.groupID = BoundariesSplitUp.GroupID
group by bg.name
order by bg.name
Thanks Jason,
any idea if it’s possible to temporary add a BoundaryGroupID to the array?
I tried
$bdryGrpCache = Get-WmiObject -Namespace ‘Root\ccm\LocationServices’ -Query “Select * From BoundaryGroupCache”
$bdryGrpCache.BoundaryGroupIDs += 16777219
It works, but the added ID is immediately removed. And my skills ended 😀 Any idea how to avoid the removal, if possible?
Thanks you.
I doubt that this is possible. I can see it being used for testing but local manipulation of these things could be pretty bad management wise so it makes sense that it just gets overwritten right away.
i dont see boundarygroupcache table in the database , please advise.
Where exactly are you looking for it and what exactly are you looking for?
Did you add the WMI class to your hardware inventory?
Hey Jason –
Great post – thanks! How were you able to determine the three “times” that clients refresh their boundary group assignment? Is it documented somewhere (a cursory search of MicrosoftDocs didn’t seem to give me anything) or is it reflected in the client logs somewhere?
Hi Nathan,
That’s info from the product group.
Thanks Jason, great article, I’m sure this will come in handy. However I have a different issue where I have removed a boundary from a boundary group( as a test). A client in that boundary, still says its part of the boundary group. We have no fallback setup. I’m having issues of clients in a second domain going across the firewall for content from the DPs instead of its own DP, assigned by boundary groups. Microsoft are stumped with this one too.
Clients won’t rediscover their boundary group until they detect a client-side network change, 25 hours, or the agent is restarted (whichever comes first).
What kind of boundaries are you using?
All IP ranges. Test machines have been turned on and off multiple times, client reinstalled. Even create a new boundary group, moved the test boundary over, restarted the machines, ran wbemtest, its now part of the new group and the old one.
Think I need to delete that old group. Is there anyway of moving the boundaries from one group to another? There are 750 boundaries to move.
Hi Jason,
I am looking for a way to exclude clients from software deplpyment when they are in particular boundary groups. I have created BoundaryGroups with IP addresses when the clients use VPN. I would like to deploy software, but the clients should only get the software if they are NOT in the desired boundary (VPN). Do you know how I can implement this as a query? Your solution here is already going in the right direction.
Thank you!
Assuming your VPN is configured for split-tunneling, why not configure the boundary group to prefer cloud sources for content?