Skip to main content

PowerShell + SCCM 2012 Tip : Get OS Inventory

Another post inspired by the daily job as a ConfigMgr Admin.

Usually while deploying applications as a best practice we check few details about the machine like the Operating System it's running on to ensure that we deploy the correct package targeted to the correct OS.

In past there have been cases where a package targeting XP was send to a Windows 7 machine or vice-versa.

So how do I check OS information :
  1. If Machine is online ;Use PowerShell or any other tool to query WMI to get the info.
  2. If Machine is offline ;Head over to SCCM Reports to see the info

We can use PowerShell to do perform the second part as well because ConfigMgr SMS namespace  provider stores this information in the class named SMS_G_System_Operating_System .

Note - The data in the class SMS_G_System_OPERATING_SYSTEM is stored as a result of the Hardware Inventory of the Win32_OperatingSystem class on a remote machine. So if the H/W Inventory has not run then this data is not available.

One can see the class and the properties on it using Get-WMIObject or Get-CIMInstance cmdlet like below:
PS C:\> Get-WmiObject -Class SMS_G_System_OPERATING_SYSTEM -Namespace Root/SMS/site_DEX -List -ComputerName DexSCCM


   NameSpace: ROOT\SMS\site_DEX

Name                                Methods              Properties
----                                -------              ----------
SMS_G_System_OPERATING_SYSTEM       {}                   {BootDevice, BuildNumber, Caption, CountryCode...}


PS C:\> Get-WmiObject -Class SMS_G_System_OPERATING_SYSTEM -Namespace Root/SMS/site_DEX -List -ComputerName DexSCCM| select -ExpandProperty properties | select Name

Name
----
BootDevice
BuildNumber
Caption
CountryCode
CSDVersion
Description
FreePhysicalMemory
FreeVirtualMemory
GroupID
InstallDate
LastBootUpTime
Locale
Manufacturer
MaxNumberOfProcesses
Name
Organization
OSLanguage
RegisteredUser
ResourceID
RevisionID
SystemDirectory
TimeStamp
TotalSwapSpaceSize
TotalVirtualMemorySize
TotalVisibleMemorySize
Version
WindowsDirectory



Note - One needs to pass the SCCM Server name to -ComputerName parameter and to -NameSpace parameter the correct namespace e.g. Root/SMS/Site_DEX (where DEX is the 3 letter site code)

So utilizing this information I wrote a function  Get-OSInfo  which works in the below order :

  • Check If Machine is online and the User running the Script has access to query WMI on the remote machine : If Yes then query Remote Machine for the OS information
  • If the Machine is offline or the User is denied access to query WMI on the remote machine then we query SCCM Server for the same.
Make a note of the property named PSComputername on the object written to pipeline this tell where the information came from (Remote machine or ConfigMgr Server).

Usage:
PS E:\> Get-OSinfofromSCCM -ComputerName dexterdc -Verbose
VERBOSE: [BEGIN]
VERBOSE: [PROCESS] Querying dexterdc for OSInfo


PSComputerName  : dexterdc
ComputerName    : dexterdc
OS              : Microsoft Windows Server 2012 R2 Datacenter Preview
ServicePack     : 
LastBootupTime  : 5/23/2014 6:06:05 AM
InstallDate     : 1/18/2014 3:29:37 PM
OSVersion       : 6.3.9431
SystemDirectory : C:\Windows\system32

VERBOSE: [END]



PS E:\> Get-OSinfofromSCCM -ComputerName dexterdc -SCCMServer dexsccm 


PSComputerName  : dexterdc
ComputerName    : dexterdc
OS              : Microsoft Windows Server 2012 R2 Datacenter Preview
ServicePack     : 
LastBootupTime  : 5/23/2014 6:06:05 AM
InstallDate     : 1/18/2014 3:29:37 PM
OSVersion       : 6.3.9431
SystemDirectory : C:\Windows\system32




PS E:\> Get-OSinfofromSCCM -ComputerName dexterdc -SCCMServer dexsccm -QuerySCCMOnly -Verbose
VERBOSE: [BEGIN]
VERBOSE: SCCM Server was supplied as an argument ...trying to open a CIM Session
VERBOSE: [BEGIN] WSMAN is responsive
VERBOSE: Operation '' complete.
VERBOSE: [BEGIN] [WSMAN] CIM SESSION - Opened
VERBOSE: Perform operation 'Query CimInstances' with following parameters, ''queryExpression' = select * from SMS_ProviderLocation where ProviderForLocalSite = true,
'queryDialect' = WQL,'namespaceName' = root\sms'.
VERBOSE: Operation 'Query CimInstances' complete.
VERBOSE: [BEGIN] Provider is located on DexSCCM.dexter.com in namespace root\sms\site_DEX
VERBOSE: [PROCESS] Querying dexsccm for OSInfo
VERBOSE: Perform operation 'Query CimInstances' with following parameters, ''queryExpression' = Select Version,CSDVersion,SystemDirectory,Installdate,LastBootuptime,
installdate,caption,Description from SMS_G_System_OPERATING_SYSTEM JOIN SMS_R_System ON SMS_R_System.ResourceID = SMS_G_System_OPERATING_SYSTEM.ResourceID where SMS_
R_System.NetbiosName='dexterdc','queryDialect' = WQL,'namespaceName' = root\sms\site_DEX'.
VERBOSE: Operation 'Query CimInstances' complete.


PSComputerName  : dexsccm
ComputerName    : dexterdc
OS              : Microsoft Windows Server 2012 R2 Datacenter Preview
ServicePack     : 
LastBootupTime  : 5/22/2014 4:24:50 PM
InstallDate     : 1/18/2014 8:59:37 PM
OSVersion       : 6.3.9431
SystemDirectory : C:\Windows\system32

VERBOSE: [END] Removing the CIM Session
VERBOSE: [END]

The code is self explanatory and there is a cool trick where I explicitly thow an exception to get inside catch block where nested try-catch block is used again.
Also have a look at the WQL query used to get the info from the ConfigMgr Server. Pretty neat ! :-B

There are a lot of Hardware inventory classes in ConfigMgr which can be used by us to inventory our environment and this should serve as a base to build upon :)

That's it for the post. If you have any suggestions or feedback please do drop a comment.


Below is the script link and gist:
http://gallery.technet.microsoft.com/Get-OS-Info-from-SCCM-d4e2858a

Popular posts from this blog

PowerShell + .psd1 files - decouple environment configuration data from code

What is environment configuration data?
Well, you might have heard the term 'configuration data' in usage with PowerShell DSC. The case for using configuration data is wherein all the input arguments are abstracted from the code being written so that this configuration data can be generated on the fly and passed to the underlying scripts or framework like DSC.

For some of our solutions being deployed at the customer site, we require a lot of input parameters e.g. different network subnets for management and storage networks, AD/DNS information etc.

Adding all these parameters to our input argument collector script was an error prone and tedious task since there were far too many input arguments. So instead of having a file to specify all input arguments was the preferred method.

This also helped us while troubleshooting the deployments since a local copy of the input arguments always persisted.


PowerShell + SCCM : WMI Scripting

Why should I use WMI, when there is a PowerShell module available for Configuration Manager (CM Module) already?

Well the cmdlets behind the scene interact with the WMI layer and if you know which WMI classes the corresponding cmdlet work with , it can be of help in future by :

Switching to native WMI calls when the CM cmdlets fail for some reason (probably bug in the CM Module).Making your scripts more efficient by optimizing the WMI (WQL query) calls, the cmdlet will query all the properties for an Object (select *) you can select only ones you need. Lastly no dependency on the CM Module, you can run these automation scripts from a machine not having the CM console installed (needed for CM module).Moreover ConfigMgr uses WMI extensively, you already have this knowledge leveraging it with PowerShell shouldn't surprise you. This post assumes you have been working with CM cmdlets (you already are versed with PowerShell), know where the WMI namespace for ConfigMgr resides and the basi…

Az.ResourceGraph - Search across all Subscriptions

Azure Resource Graph is an amazing tool in the belt of Az Ops team. It allows to quickly search across all your subscriptions (does it?).

Started using Az Resource graph with that pretext that the queries I ran will be run against all the subscriptions I have read access to, Yes it will but there is a catch here!

I mostly use Az.ResourceGraph PowerShell module (Why? another post)

Found the solution by digging into the source code for the Search-AzGraph cmdlet, if the subscriptions are not specified explicitly then the cmdlet uses a method named GetSubscriptions()

Below is a snippet of the method def:

The catch is that if no subscriptions are supplied it defaults to subscriptions in the default context. I am not really sure but some of the subscriptions which I can see when running Get-AzSubscription were missing when I ran the below:

(Get-AzContext).Account.ExtendedProperties.Subscriptions

So, the trick is to set the PSDefaultParameterValues for the Search-AzGraph cmdlet to include all the s…