Saturday, April 19, 2014

PowerShell + SCCM 2012 R2: Get the Device/ User Info WMI Way

This is in continuation of my last post on Using PowerShell to get client information  
In this post will be exploring on the ways to do the same thing using WMI/CIM, Why ?
With WQL syntax we can ask for only the properties we need rather than getting everything back.

The post will cover 3 topics:
  1. Query individual Device in CM using WMI/CIM
  2. Query Members of a Device Collection using WMI/CIM
  3. Query Users in a User Collection using WMI/CIM
To get the number of properties got back from a call to Get-CMDevice use Get-Member and Measure-Object like below:

Most of the properties returned back may be empty depending on how you are using ConfigMgr e.g if you use endpoint protection than those attributes in the class will be populated else will be empty.

Now if you see the output of Get-CMDevice is actually is a result of the SMS_CombinedDeviceResources

Let me tell you a little secret :-$ ...if you are looking forward to explore WMI part of ConfigMgr and have a doubt on which Class to look for, then piping the output of the Cmdlets with the ConfigurationManager Module to Get-Member gives you a hint.

The cmdlets shipped with (written in C#) the Module essentially makes WMI calls and then expose the results back to us that's why IResultObject in the Typename (above screenshot) :-B

So let's explore a bit the SMS_CombinedDeviceResources class...using the Get-CIMClass cmdlet.

Note - will be using the $PSDefaultParameters as mentioned in my earlier posts to set the Computername and Namespace parameter to point to the ConfigMgr Server.

We can see a lot of properties defined in this class:

Query individual Device using WMI/CIM

To get this information for a client can be a simple WMI call where you specify a filter for the Name property like below:

Get-CimInstance -ClassName SMS_CombinedDeviceResources -Filter 'Name="DEXTERDC"'

But the good thing about using the WMI/ CIM cmdlets directly is that we can use the WQL query to select only the properties we want (see below):

Get-CimInstance -Query "Select Name,LastMPServerName,deviceos from SMS_CombinedDeviceResources where Name='DexterDC'"

Note that all the extra properties show up as blank (other than those specified with Select statement), this will save the network bandwidth and will be efficient when we are processing say hundreds or thousands of clients.

Query Members of a Device Collection using WMI/CIM

If you have read few of my earlier posts then you would know that all the collections we create are an instance of the class SMS_Collection. So let's go ahead and do a WMI query to get the object back for the "All Systems" collection.

 Get-CimInstance -ClassName SMS_Collection -Filter 'Name="All Systems"'

Now out of all the properties listed the one which stands aside is the property named 'MemberClassName'. If you query this Class mentioned in the property MemberClassName then you get back all the members of the collection..I think you figured that out already ;)

Below is the value of the property MemberClassName for my "All Systems" collection
PS> (Get-CimInstance -ClassName SMS_Collection -Filter 'Name="All Systems"').MemberClassName


So let's do a WMI Call for this class:

You can see it got all the machines which were member of the 'All Systems' Collection

Now using the WQL query to optimize this a bit :

Get-CimInstance -query 'Select Name,IsClient,LastMPServerName,DeviceOS from SMS_CM_RES_COLL_SMS00001' | select -Property Name,IsClient,LastMPServerName,DeviceOS

I pipe it to the Select-Object cmdlet to get the properties I wanted as rest every property is empty.

To give an idea on the efficiency part see below:

PS> Measure-Command {  Get-CMDeployment -CollectionName 'All Systems'}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 1
Milliseconds      : 55
Ticks             : 10554314
TotalDays         : 1.22156412037037E-05
TotalHours        : 0.000293175388888889
TotalMinutes      : 0.0175905233333333
TotalSeconds      : 1.0554314
TotalMilliseconds : 1055.4314

PS> Measure-Command  {Get-CimInstance -query 'Select Name,IsClient,LastMPServerName,DeviceOS from SMS_CM_RES_COLL_SMS000
01' }

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 173
Ticks             : 1738179
TotalDays         : 2.01178125E-06
TotalHours        : 4.828275E-05
TotalMinutes      : 0.002896965
TotalSeconds      : 0.1738179
TotalMilliseconds : 173.8179

This is pretty explanatory right ! This would be pretty significant difference if there are a lot of members in the Collection.

Query Users in a User Collection using WMI/CIM

Now there are User Collections too so how do we query the members in it. Well easy the same way we did it with Device Collections. :P

Well the difference is in the type of collection:
PS> (Get-CimInstance -ClassName SMS_Collection -Filter 'Name="All Systems"').CollectionType
PS> (Get-CimInstance -ClassName SMS_Collection -Filter 'Name="All Users"').CollectionType
So if we wanted to get the members of the collection "All Users" then below is a one liner to do that:

Get-CimInstance -ClassName  (Get-CimInstance -ClassName SMS_Collection -Filter 'Name="All Users"').MemberClassName |

 Select Name,SMSID

You can see the Class to which a User in CM belongs is SMS_CombinedUserResources which has few properties defined in it. 

[UPDATE} I was writing a function which will do all of the above things shown for me..there is a switch by the name $PropertySelect (also when I tried using $SelectProperty it gave me an error saying that 'The parameter name "SelectProperty" is reserved for future use.' ) which will give an option to select properties in Out-Gridview Window and these properties will only be retrieved ..pretty cool B-)
That's it for today's post. :) :)