Creating a collection of VPN devices
With so many people working from home these days, handling devices that are connected via VPN has become challenging for many companies. Looking at this from the ConfigMgr perspective, there are several aspects that we might want to do differently, depending on if a device is connected via VPN or on-premise. We might want to handle patching differently, might want to adjust a few client settings, etc.
Anoop C Nair has published an interesting post about how to “Use existing SCCM config to help reduce VPN Bandwidth“, where he goes over different options on how to reduce the impact on the VPN bandwidth.
However, that still doesn’t really tell us, which devices are actually connected via VPN.
How to identify a device connected via VPN
There are different ways to identify, if a device is connected via VPN. One of the easiest in ConfigMgr is simply based on the boundary. And that’s the one we will be concentrating on in this post. You very likely have one or multiple IP ranges for your VPN clients. And I assume, that you have already created boundaries based on these IP ranges. And all these VPN related boundaries should be within one Boundary Group, that has no other boundaries assigned. For certain scenarios it might even be useful to have multiple boundary groups, but that doesn’t really change our approach. The key aspect here is, that this VPN Boundary Group(s) only contain VPN related boundaries.
Luckily Mike Terrill just described already in detail how to create these VPN related boundaries and boundary groups in his post about “Forcing Configuration Manager VPN Clients to get patches from Microsoft Update“. Going forward I’ll assume this or a similar setup.
The boundary group is the key
With this setup, every client who is connected via VPN and got an IP address from these IP ranges will now be in the VPN boundary group. Starting in version 2002 (Yes, the ConfigMgr versions this year confuse everyone), ConfigMgr added the “Boundary Group(s)” column to the devices node and when showing members of a device collection (https://docs.microsoft.com/en-us/configmgr/core/servers/deploy/configure/boundary-groups#bkmk_show-boundary).
Which made me think, as this information is available within the ConfigMgr console, we should theoretically be able to use this information to create a collection that contains all devices, that are connected via VPN. As this information seems to come from the Fast Channel it should also be pretty up to date as well. However, as the documentation says that it updates “at most every 24 hours”, this could be a wrong assumption. This needs some further testing to see how timely accurate it actually is.
So where do we now find this information? Digging through the internals of ConfigMgr, I found the SMS_CombinedDeviceResources class, which has the property “BoundaryGroups”. It actually has lots of other interesting properties as well, which basically matches the list of columns that are available when listing devices of a collection. So I’d say it’s fair to assume that this is the underlying class that is used by the ConfigMgr console.
Based on this information, all it takes now is to create a query where we join this class and filter based on the BoundaryGroups property. The query statement could look like:
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 JOIN SMS_CombinedDeviceResources ON SMS_CombinedDeviceResources.ResourceID = SMS_R_SYSTEM.ResourceID WHERE SMS_CombinedDeviceResources.BoundaryGroups LIKE "%VPN%"
Assuming, that the boundary group(s) has “VPN” in its name. Please adjust, if you used a different naming for your boundary group. The query evaluates relatively quick, even in large environments. Might even want to enable incremental updates on the collection, so new machines on VPN are added as quickly as possible.
Boundary Group Caching
If you are not yet on ConfigMgr version 2002, you can get similar behavior by leveraging the information from Boundary Group Caching, which has been added in version 1511. It’s basically the same source of information, however on default, it’s only available on the client. Jason Sandys has a great post about “Boundary Group Caching“, where it is stored and how to extend your current hardware inventory to collect this information and make it available this way.
If you added this information according to Jason’s post, you could get a similar result using
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_BOUNDARYGROUPCACHE ON SMS_G_System_BOUNDARYGROUPCACHE.ResourceId = SMS_R_System.ResourceId WHERE SMS_G_System_BOUNDARYGROUPCACHE.BoundaryGroupIDs LIKE "%XXXXXXX%"
Where XXXXX is the internal ID of the boundary group. We can’t really join the BoundaryGroupIDS to SMS_BoundaryGroup and use the name, as this value is a comma separated list of all boundary groups the client is a member of. Same reason for using a LIKE, rather than an equal. This shouldn’t be a big problem, as we assume you are only dealing with a single, or at max very few boundary groups.
Biggest drawback here though, as it’s based on hardware inventory, the information is not as up to date as you might need it to be.
Another way on getting similar results could be leveraging the SMS_Boundary class and join it to the IPSubnets property of SMS_R_System. However this will not be feasible for this scenario, as the boundaries need to be configured as IP Subnet and not as an IP Range. The bad part being, that it needs to match the subnet as it’s configured on the client side. VPN solutions typically take IP ranges and assign a single IP subnet with a 255.255.255.255 network mask to each VPN clients. So to be able to join them properly, you would have to replicate this configuration on the boundary side, which would mean you end up with thousands of micro boundaries. Also this is again based on hardware inventory, so might lack timely accuracy. I just wanted to have it listed here, as it actually has some other use cases, if you have boundaries defined as IP subnets and would like to create a collection based on this information. However, if you are on version 2002, I’d definitely recommend using SMS_CombinedDeviceResources for those cases as well.
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 JOIN SMS_Boundary ON SMS_Boundary.Value = SMS_R_System.IPSubnets WHERE SMS_Boundary.DisplayName LIKE "%VPN%"