SQL Server Product and Version Reporting with SCCM

, , , , , , , , , ,

SQL licensing is always a pain but this report should make it a little easier…

Report release history

Previous report version

Also published on my blog

This is the second iteration of my SQL version report. When I look back on my previous work I always cringe and this was no exception. A while back, I received a request to add the SQL key to the report, so I began examining the old code. Horrified by the things that I found laying dormant there, I scrapped everything and started anew.

The report is brand new with a lot more info, smaller database footprint and much better coding.


  • Do not modify or revemove the previous version until you verify that this version has all the data you need!
  • Use a test environment for validation!
  • Back-up your configuration.mof file before any changes!
  • Test the configuration.mof using mofcomp.exe on a test machine first!

This version is compatible with the previous version, they can live side by side.

Hardware inventory extension needs to be done on the top of your hierarchy.



  • Test environment
  • Downloads (Right click →Download linked file)
# HWI Extension
HWI EXT SQL Server Products.mof
# HWI Definitions
HWI DEF SQL Server Products.mof
# SSRS Report
SW SQL Server Products.rdl
  • SQL Stored Procedure →‘Create the SQL Stored Procedure’ section.

HWI Extension

The extension needs to be added to the configuration.mof file in \Inboxes\clifiles.src\hinv\

  • Look for the section below at the end of the configuration.mof file. The extension needs to be added between the “Added extensions start/end” headers.
  • Uncomment the “Old SQL extension cleanup” section to remove the old extension classes from the clients repository if needed.
  • Use a test environment for validation as described in the ‘Test and Validation’ header after the Installation section.
// Added extensions start 
// Added extensions end 

Always use a test environment before any changes in production!

Never create any extensions outside of the “Added extensions start/end” headers.
Try to have consistent formatting inside these headers.
Never modify anything outside these headers.
Watch for other previous extensions and use clear delimitation between them.

  • Apply changes in production
## Compile file on the CAS/PSS
Compiling the configuration.mof file in the hinv folder on the CAS/PSS, will trigger the distribution and compilation on all machines in your environment on the next machine policy evaluation.
mofcomp.exe \Inboxes\clifiles.src\hinv\Configuration.mof

Implement HWI extension in production

HWI Definitions

You need to add the new class definitions to the Default Client Settings

  • Import definitions.

Click on Import and select the HWI DEF SQL Server Products.mof file

Review the classes and click on Import.

Make sure the new extension classes are enabled and click OK.

DO NOT DELETE the old extension definitions if you still want to use the old report!

Test and Validation


Use mofcomp.exe to check if configuration.mof was correctly modified, and implement the changes.

## Check syntax
mofcomp.exe -check \Configuration.mof
## Compile file 
Compiling the configuration.mof file in the hinv folder on the CAS/PSS, will trigger the distribution and compilation on all machines in your environment on the next machine policy evaluation.
mofcomp.exe \Configuration.mof

Compling the configuration.mof is done on a test environment here!

Saving and compiling the configuration.mof file in the hinv folder on the CAS/PSS, will trigger the distribution and compilation on all machines in your environment on the next machine policy evaluation.


Use PowerShell to check if the new classes have been created in WMI

## Check if the new classes are present in WMI
/* The machine must have at least one version of SQL installed in order for these classes to be created */
#  Get SQL 2017 class
Get-CimClass -ClassName SQL_2017_Property
#  Get SQL 2014 class
Get-CimClass -ClassName SQL_2014_Property
#  Get SQL 2012 class
Get-CimClass -ClassName SQL_2012_Property
#  Get SQL 2008 class
Get-CimClass -ClassName SQL_2008_Property
#  Get SQL Legacy class
Get-CimClass -ClassName SQL_Legacy_Property
#  Get SQL ProductID class
Get-CimClass -ClassName SQL_ProductID


Use SSMS (SQL Server Management Studio) to check if the views are created in the CM database

Import the SSRS Report

Upload Report to SSRS

  • Start Internet Explorer and navigate to http:///Reports
  • Choose a path and upload the previously downloaded report file.

Configure Imported Report

Create the SQL Stored Procedure

The usp_PivotWithDynamicColumns is needed in order to maximize code reuse and have a more sane and sanitized data source.

  • Copy paste the code below in SSMS
  • Change the in the USE statement to match your Site Code.
  • Click Execute to add the usp_PivotWithDynamicColumns stored procedure to your database.

You might need additional DB access to install the support function!
Allow some time for the policy to be downloaded or force a policy refresh.

Allow some time for the data to be gathered or force a HWI collection.
This report was created with SQL 2017 Reporting Services, you might need to remove some report elements if you use an older version.


Report preview


HWI Extension

For reference only, you can download the file in the ‘Prerequisites’section.

HWI Definitions

For reference only, you can download the file in the ‘Prerequisites’section.

SQL Query

For reference only, the report includes this query.

VB Support Function

For reference only, the report includes this function.

Credit to Jakob Bindslet and Chrissy LeMaire.

Use Github for 🐛 reporting, or 🌈 and🦄 requests

Quick and Dirty SCCM Application Deployment Reporting

, , , ,

For this blog, I’m going to go over a very basic script I wrote to quickly get application deployment statuses without having to use the Configuration Manager GUI console. I find the ReportingDeployments tab very slow to respond, and you still have to dig into each individual app if you want details.  What this function does is allow you to specify what you think is the name of the application and it will find anything like it, allow you to select the one you want, and then it will run a deployment summarization and output the results.


Application Deployment
Function called with the correct name of the package

In this example, “Tanium Client” is the actual name of a software package, so it doesn’t need to pop up a prompt asking us which one we actually wanted.

Application Deployment
Function called with a keyword instead of the full package name
Application Deployment
After package was selected from the pop up
In the above two images, I didn’t remember the full name of my Tripwire deployments, so I just typed “Tripwire” and let it look for it for me.
The Code:
This is a fairly simple piece of code, but I wrote it to run quickly.  It first checks to see if the name you gave it when running already matches a software package. If not, it runs a WMI query (much faster than using Get-CMApplication with a where-object piped on) to look for anything like what you entered. It puts all results into an array which then selects the LocalizedDisplayName and filters out duplicates. Those unique values are then handed over to Out-GridView, which thanks to the -passthru flag assigns the selected result to our original $SoftwareName variable.  You’ll also see that I have to specify that I want the “.localizeddisplayname” NoteProperty. If you don’t do this, you’ll see the selected software name as “@LocalizedDisplayName={‘Whatever your name was’}”
After that selection process, everything proceeds as normal. It gets the CMDeployment object for that application and runs the Invoke-CMDeploymentSummarization cmdlet which refreshes the deployment status, gets you current numbers, etc.  After that, I have it get the deployment again and select what I found to be the relevant values for a list formatted report.  Because SummarizationTime is done in UTC, I have it convert to client local time for ease of reporting, and I also go ahead and do a quick math expression for the percent success, which is done with the Round function so we don’t get a dozen decimal places of needless precision.   The Query Time value was mostly tacked on at the end so the people I was getting this information for could see that the data was current.
Hopefully this is useful for someone out there. Thanks for reading!