Yes, another one.

And if you include other languages, like VBScript, there’s at least a dozen or so I’ve run across via a web search.

mine_detector

First – The Models

The term “model”, in this context, refers to the method by which the challenge is approached.  One of my college classmates used to say “if you approach it from the front, that would be the ‘Missionary model’.  But if you approach it from behind could be the ‘Government model’“, but I won’t go there.

Seriously, there are multiple models, or approaches, available:

Model 1 – is to run the script on, or via remote invocation on, the remote site system (aka Management Point, SMS Provider, etc.).

Model 2 – is to run the script from a client and do everything purely remote.

Model 3 – is to run the process, as a whole, in two-parts: extraction and compilation.

A classic example of model 2 would be Garth Jones’ script at EnhanceSoft.  A classic example of model 3 would be Raphael Perez’s script at wherever he hangs his hat now.  Both of these are very nice indeed, and are worth the time to explore.  The example shown below uses model 2.

Aside from this, there are other model aspects to consider, ponder, pontificate and rub chins until they’re raw.  Code factoring. Data isolation. Input vectors, and so forth.

For this example, I decided (on 2 hours of sleep) to encapsulate (I love that word) the configuration parameters in an XML file.  Then script, being PowerShell, I’ve divided into a function module and a runtime script, and the output is HTML (for portability).  The configuration parameters include consistent modular groups, each of which contains a Caption, WMI Class Name, Properties List, Filtering Criteria, Tabular Mode (I’ll explain later), and Sort-by property name.

The tabular mode refers to a data construct being singular or plural.  For example, Win32_ComputerSystem is singular, whereas Win32_Service is plural (returns more than one instance by default).  In this context, I sort-of pivot the table based on “single” or “multi” table mode.

Function Conjunction

This version of the script is one-server-at-a-time.  The current version in test allows batch input (from CLI or file) as well as “mining” where by it reads hierarchy servers and builds a dynamic list of what to inventory (CAS, Primaries, Secondaries, DP’s, RP’s, etc.). The output for this version is one HTML file.  In the current (test) version, it’s still one file per server, but creates an index.htm file to act as a directory of sorts.

The Files

There are a handful of files involved with this example:

  • Get-CmInventory.ps1 (runtime script)
  • cminv.psm1 (function module)
  • queries.xml (configuration parameters)
  • default.css

The CSS file is optional, but helps “pretty-up” the HTML output so you don’t run over to the water fountain to flush your eyes out.

TIP: If you copy/paste this into Visual Studio Code, or Notepad++, or PowerShell ISE, run it through a format extension to “pretty-it-up”.  Also, be wary of ‘smart-quotes’ and smart -hyphens, which can cause the interpreter to puke its meal up.

The PowerShell Run-Time Script: Get-CmInventory.ps1

<#
.SYNOPSIS
  Get-CmxInventory.ps1 is a general-purpose
  inventory script for AD/Server/ConfigMgr
.DESCRIPTION
  This script is for querying a remote server
  or a list of remote servers, to generate a 
  report of inventory data for Windows Server, 
  Active Directory, and System Center Configuration
  Manager, as well as some selected aspects of the
  site SQL Server instances.
.PARAMETER CmSiteServers
  FQDN of ConfigMgr site servers to query
  comma-delimited list
.PARAMETER CustomerName
  Name of customer to use for heading of report file
  (default is blank)
.PARAMETER Scope
  What to query: 'All','CM','Server','AD'
  (default is 'CM')
.PARAMETER Granularity
  Verbosity: 'Basic','Advanced','Extreme','Insane'
  (default is 'Basic')
.PARAMETER ReportFolder
  Path for report file 
  (default is script path)
.NOTES
  Version: 1605.1701
  Author: David Stein
.LINK
  https://skatterbrainz.wordpress.com
#>

param (
  [parameter(Mandatory=$True)] 
    [ValidateNotNullOrEmpty()]
    [string] $CMSiteServers,
  [parameter(Mandatory=$True)] 
    [ValidateNotNullOrEmpty()]
    [string] $CustomerName,
  [parameter(Mandatory=$False)]
    [ValidateSet('AD','CM','Server','All')]
    [string] $Scope = "CM",
  [parameter(Mandatory=$False)] 
    [ValidateSet('Basic','Advanced','Extreme','Insane')]
    [string] $Granularity="Basic",
  [parameter(Mandatory=$False)] 
    [string] $ReportFolder = ""
)
$ScriptVersion = "1605.1701"
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
if ($ReportFolder -eq "") { $ReportFolder = $ScriptPath }
$cred = Get-Credential
Import-Module "$ScriptPath\cminv.psm1"
$xmlFile = "$ScriptPath\queries.xml"
$rundate = $(Get-Date).ToLongDateString()
$rundate += ", $($(Get-Date).ToLongTimeString())"
$runhost = $env:COMPUTERNAME
$runuser = $env:USERNAME

foreach ($CmSiteServer in $CmSiteServers.split(',') ) {
  $reportFile = "$ReportFolder\$CMSiteServer.htm"
  $pageset = @"
<!DOCTYPE html>
<html lang="en-US">
 <head>
 <title>$CMSiteServer</title>
 <meta charset="utf-8" />
 <link rel="stylesheet" href="default.css" />
 </head>
 <body>
 <h1>$CMSiteServer</h1>
 <h3>$CustomerName</h3>
 <table border='1'>
 <tr>
 <td class='bggray'>Run Date/Time</td>
 <td class='bggray'>Run From</td>
 <td class='bggray'>Run By</td>
 <td class='bggray'>Run Params</td>
 </tr>
 <tr>
 <td>$rundate</td>
 <td>$runhost</td>
 <td>$runuser</td>
 <td>$CMSiteServer, $Scope, $Granularity</td>
 </tr>
 </table>
"@

  if (Test-Path -Path $xmlFile) {
    [xml]$qdata = Get-Content -Path $xmlFile
    $qLevel = ("Basic,Advanced,Extreme,Insane").split(",").IndexOf($Granularity) + 1
    Write-Host "Query-Level: $qLevel ($Granularity)" -ForegroundColor Green
    if (($Scope -eq "Server") -or ($Scope -eq "All")) {
      $pageset += "<h1>Computer System</h1>"
      $qset1 = $qdata.queries.query | where {$_.type -eq "os" -and $_.level -le $qLevel}
      foreach ($qx in $qset1) {
        $group = $qx.caption
        $class = $qx.class
        $space = $qx.space
        $criteria = $qx.criteria
        $sort = $qx.sort
        $proplist = $qx.props
        $mode = $qx.mode
        $dataset = Get-CmxPropSet -Caption $group -ComputerName $CMSiteServer -Space $space -Cred $Cred -ClassName $class -PropList $proplist -Criteria $criteria -TableMode $mode -Sorting $sort
        $pageset += $dataset
      }
    }
    if (($Scope -eq "CM") -or ($Scope -eq "All")) {
      $SiteCode = Get-CmxCmSiteCode -ComputerName $CMSiteServer -Cred $Cred
      Write-Host "site code: $SiteCode" -ForegroundColor Cyan
      $space = "root\SMS\site_$SiteCode"
      try {
        Get-WmiObject -ComputerName $CmSiteServer -Class SMS_Boundary -Namespace $space -Cred $Cred -ErrorAction SilentlyContinue
        Write-Host "wmi connection: successful"
        $continue = $True
      }
      catch {
        Write-Host "error: wmi connection not allowed. check security context." -ForegroundColor Red
        $continue = $False
      }
      if ($continue -eq $true) {
        Write-Host "namespace: $Space" -ForegroundColor Cyan
        $pageset += "<h1>Configuration Manager</h1>"
        $qset2 = $qdata.queries.query | where {$_.type -eq "cm" -and $_.level -le $qLevel}
        if ($SiteCode -ne "") {
          foreach ($qx in $qset2) {
            $group = $qx.caption
            $class = $qx.class
            $criteria = $qx.criteria
            $sort = $qx.sort
            $proplist = $qx.props
            $mode = $qx.mode
            $dataset = Get-CmxPropSet -Caption $group -ComputerName $CMSiteServer -Space $space -Cred $Cred -ClassName $class -PropList $proplist -TableMode $mode -Criteria $criteria -Sorting $sort
            $pageset += $dataset
          }
        }
      }
    }
    if (($Scope -eq "AD") -or ($Scope -eq "All")) {
      <#
      coming later
      #>
    }
  }
  else {
    Write-Host "error: $xmlFile not found."
  }

  $pageset += @"
<!-- ---------------------- END OF REPORT ------------------ -->
<p>*** CONFIDENTIAL INFORMATION: NOT FOR USE WITHOUT EXPLICIT CONSENT OF CUSTOMER ***</p>
<footer>Version $ScriptVersion. Copyright &copy; 2016 David Stein. All rights reserved.</footer>
</body></html>
"@

  Write-Host "saving report as $reportFile"
  Set-Content -Path $reportFile -Value $pageset 
}
Write-Output "processing complete."

The PowerShell Function Module:  cminv.psm1

<#
.SYNOPSIS
  PowerShell functions module for AD/SCCM/Windows inventory
.DESCRIPTION
  Functions for running remote inventory queries
  against a helpless victimized Windows server
  which may or may not have System Center Configuration Manager
  installed on it.
.NOTES
  Version: 1605.1701
  Author: David Stein
.LINK
  https://skatterbrainz.wordpress.com
#>

<#
.SYNOPSIS
  Get-CmxPropName
.DESCRIPTION
  Returns base name or alias name for column
.PARAMETER StringVal
  String which may contain base name and alias or just base name
.PARAMETER Part
  String to indicate 'Realname' or 'Alias'
.EXAMPLE
  $column = "A=Alpha"
  Get-CmxPropName -StringVal $column -Part 'Alias'
  returns: "Alpha"
#>

function Get-CmxPropName {
  param (
    [parameter(Mandatory=$True)] [string] $StringVal,
    [parameter(Mandatory=$True)] 
    [ValidateSet('Realname','Alias')] [string] $Part
  )
  $px = $StringVal.split("=")
  if ($px.length -eq 2) {
    if ($Part -eq 'Realname') {
      $result = $px[0]
    }
    else {
      $result = $px[1]
    }
  }
  else {
    $result = $px
  }
  return $result
}

<#
.SYNOPSIS
  Get-CmxLabels
.DESCRIPTION
  Return column name labels (base name or alias values)
.PARAMETER DataList
  comma-delimited string list of column names
.EXAMPLE
  $columns = "A=Alpha,Bravo,C=Charlie"
  Get-CmxLabels
 
#>

function Get-CmxLabels {
  param (
    [parameter(Mandatory=$True)] [string] $DataList
  )
  $result = ""
  foreach ($col in $DataList.split(",")) {
    $cset = $col.split('=')
    if ($cset.length -eq 2) {
      $result += ",$($cset[1])"
    }
    else {
      $result += ",$($cset[0])"
    }
  }
  return $result.substring(1)
}

<#
.SYNOPSIS
  Convert-CmxFormat
.DESCRIPTION
  Convert enumerated values into string labels
.PARAMETER ClassName
  WMI class name
.PARAMETER PropertyName
  WMI class property name
.PARAMETER Value
  Value to convert into readable form
.EXAMPLE
  Convert-CmxFormat -ClassName "Win32_LogicalDisk" -PropertyName "DriveType" -Value 3
  return: "Local Disk"
#>

function Convert-CmxFormat {
  param (
    [parameter(Mandatory=$True)] [string] $ClassName,
    [parameter(Mandatory=$True)] [string] $PropertyName, 
    [parameter(Mandatory=$False)] $Value
  )
  $test = $PropertyName.ToUpper()
  switch ($test) {
    {($_ -eq "TOTALPHYSICALMEMORY") -or ($_ -eq "SIZE") -or ($_ -eq "FREESPACE") -or ($_ -eq "PACKAGESIZE")} {
      $x = [math]::Round($Value / 1GB, 0)
      $x = "$x GB"
      break;
    }
    "CURRENTTIMEZONE" {
      $x = [math]::Round($Value / 60, 0)
      $x = "GMT $x Hours"
      break
    }
    "DRIVETYPE" {
      switch ($Value) {
        1 {$x = "No Root Directory"; break}
        2 {$x = "Removable Disk"; break}
        3 {$x = "Local Disk"; break}
        4 {$x = "Network Drive"; break}
        5 {$x = "Compact Disc"; break}
        6 {$x = "RAM Disk"; break}
        default {$x = "Unknown"; break}
      }
      break
    }
    "COLLECTIONTYPE" {
      switch ($Value) {
        1 {$x = "User"; break}
        2 {$x = "Device"; break}
        default {$x = "Other"; break}
      }
      break
    }
    "STATUS" {
      switch ($ClassName.ToUpper()) {
        "SMS_SITESYSTEMSUMMARIZER" {
          switch ($Value) {
            0 {$result = "Green"; break}
            1 {$result = "Yellow"; break}
            2 {$result = "Red"; break}
          }
        }
        default {$x = $Value; break}
      }
      break
    }
    "CHASSISTYPES" {
      switch ([int]$Value) {
        1 {$x = "Other"; break}
        2 {$x = "Unknown"; break}
        3 {$x = "Desktop"; break}
        4 {$x = "Low Profile Desktop"; break}
        5 {$x = "Pizza Box"; break}
        6 {$x = "Mini Tower"; break}
        7 {$x = "Tower"; break}
        8 {$x = "Portable"; break}
        9 {$x = "Laptop"; break}
       10 {$x = "Notebook"; break}
       11 {$x = "Hand Held"; break}
       12 {$x = "Docking Station"; break}
       13 {$x = "All in One"; break}
       14 {$x = "Sub Notebook"; break}
       15 {$x = "Space-Saving"; break}
       16 {$x = "Lunch Box"; break}
       17 {$x = "Main System Chassis"; break}
       18 {$x = "Expansion Chassis"; break}
       19 {$x = "SubChassis"; break}
       20 {$x = "Bus Expansion Chassis"; break}
       21 {$x = "Peripheral Chassis"; break}
       22 {$x = "Storage Chassis"; break}
        23 {$x = "Rack Mount Chassis"; break}
       24 {$x = "Sealed-Case PC"; break}
       default {$x = "UNKNOWN"; break}
      }
      break
    }
    "INSTALLSTATE" {
      if ($Value -eq 1) {
        $x = "Installed"
        break
      }
      else {
        $x = ""
        break
      }
      break
    }
    "DRIVETYPE" {
      switch ($Value) {
        3 {$x = "Fixed Disk"; break}
        default {$x = $Value; break}
      }
      break
    }
    "HOTFIXID" {
      if ($Value.substring(0,2).ToLower() -eq "kb") {
        $tmp = $Value.substring(2)
        $x = "<a href=`"https://support.microsoft.com/en-us/kb/$tmp`" target=`"_blank`">$Value</a>"
      }
      else {
        $x = $Value
      }
      break
    }
    "PRIORITY" {
      switch ($Value) {
        1 {$x = "High"; break}
        2 {$x = "Normal"; break}
        3 {$x = "Low"; break}
      }
      break
    }
    "FEATURETYPE" {
      switch ($Value) {
        1 {$x = "Application"; break}
        2 {$x = "Program"; break}
        3 {$x = "MobileProgram"; break}
        4 {$x = "Script"; break}
        5 {$x = "SoftwareUpdate"; break}
        6 {$x = "Baseline"; break}
        7 {$x = "TaskSequence"; break}
        8 {$x = "ContentDistribution"; break}
        9 {$x = "DistributionPointGroup"; break}
        10 {$x = "DistributionPointHealth"; break}
        11 {$x = "ConfigurationPolicy"; break}
        default {$x = ""; break}
      }
      break
    }
    "PACKAGETYPE" {
      switch($Value) {
        0 {$x = "Regular software distribution package"; break}
        3 {$x = "Driver package"; break}
        4 {$x = "Task sequence package"; break}
        5 {$x = "Software update package"; break}
        6 {$x = "Device setting package"; break}
        257 {$x = "Image package"; break}
        258 {$x = "Boot image package"; break}
        259 {$x = "Operating system install package"; break}
      }
      break
    }
    "FLAGS" {
      switch ($ClassName.ToUpper()) {
        "SMS_SIIB_CONFIGURATION" {
          switch ($Value) {
            0 {$x = "Secondary"; break}
            1 {$x = "Primary"; break}
          }
          break
        }
        "SMS_SCI_CLIENTCOMP" {
          switch ($Value) {
            0 {$x = "Not Enabled"; break}
            1 {$x = "Enabled"; break}
            default {$x = "Automatic"; break}
          }
        }
          default {
          $x = $Value
          break
        }
      }
      break
    }
    default {$x = $Value; break}
  }
  return $x
}

<#
.SYNOPSIS
  Get-CmxPropSet
.DESCRIPTION
  Return WMI query results in a string table format
.PARAMETER ComputerName
  Name of computer to query
.PARAMETER Space
  WMI namespace to execute query against
.PARAMETER ClassName
  WMI class name
.PARAMETER PropList
  WMI class property names (comma-delimited string list)
.PARAMETER TableMode
  "single" or "multi" for table row format
.PARAMETER Sorting
  WMI property name to sort by
.PARAMETER Criteria
  WMI query condition (optional)
.EXAMPLE
  Get-CmxPropSet -ComputerName "cm1.contoso.com" `
  -Caption "Logical Disks" `
  -Space "root\cimv2" `
  -ClassName "Win32_LogicalDisk" `
  -PropList "DeviceID=Drive,DriveType=Type,Size" `
  -TableMode "multi" `
  -Sorting "DeviceID" `
  -Criteria ""
#>

function Get-CmxPropSet {
  param (
    [parameter(Mandatory=$True)] [string] $Caption,
    [parameter(Mandatory=$True)] [string] $ComputerName,
    [parameter(Mandatory=$False)] [string] $Space = "root\cimv2",
    [parameter(Mandatory=$True)] [string] $ClassName,
    [parameter(Mandatory=$True)] [string] $PropList,
    [parameter(Mandatory=$True)] [string] $TableMode,
    [parameter(Mandatory=$False)] [string] $Sorting = "",
    [parameter(Mandatory=$False)] [string] $Criteria = "",
    [parameter(Mandatory=$True)] $Cred
  )
  $result = "<h2>$Caption</h2>"
  Write-Host "querying [WMI]: $Caption" -ForegroundColor Cyan
  $labels = Get-CmxLabels -DataList $PropList
  if ($TableMode -eq "multi") {
    $result += "<table border='1'><tr><td class=`"bggray`">" + $labels.Replace(",", "</td><td class=`"bggray`">") + "</td></tr>"
  }
  else {
    #$result += "<table border='1'>"
  }
  if ($Criteria -ne "") {
    if ($Sorting -ne "") {
      try {
        $wmiData = Get-WmiObject -Namespace $Space -Class $ClassName -ComputerName $ComputerName -Filter $Criteria -Credential $Cred -ErrorAction SilentlyContinue | Sort-Object $Sorting
      }
      catch {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        Write-Host "error: $ErrorMessage :: $FailedItem" -ForegroundColor DarkYellow
      }
    }
    else {
      try {
         $wmiData = Get-WmiObject -Namespace $Space -Class $ClassName -ComputerName $ComputerName -Filter $Criteria -Credential $Cred -ErrorAction SilentlyContinue
      }
      catch {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        Write-Host "error: $ErrorMessage :: $FailedItem" -ForegroundColor DarkYellow
      }
    }
  }
  else {
    if ($Sorting -ne "") {
      try {
        $wmiData = Get-WmiObject -Namespace $Space -Class $ClassName -ComputerName $ComputerName -Credential $Cred -ErrorAction SilentlyContinue | Sort-Object $Sorting
      }
      catch {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        Write-Host "error: $ErrorMessage :: $FailedItem" -ForegroundColor DarkYellow
      }
    }
    else {
      try {
        $wmiData = Get-WmiObject -Namespace $Space -Class $ClassName -ComputerName $ComputerName -Credential $Cred -ErrorAction SilentlyContinue
      }
      catch {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        Write-Host "error: $ErrorMessage :: $FailedItem" -ForegroundColor DarkYellow
      }
    }
  }
  $rows = 0
  $cols = $labels.split(",").length + 1
  foreach ($row in $wmiData) {
    if ($TableMode -eq "multi") {
      $result += "<tr>"
      foreach ($propset in $proplist.split(",")) {
        $pname = Get-CmxPropName -StringVal $propset -Part 'Realname'
        $xname = Get-CmxPropName -StringVal $propset -Part 'Alias'
        [string]$pv = $row.GetPropertyValue("$pname")
        $npv = Convert-CmxFormat -ClassName $ClassName -PropertyName $pname -Value $pv
        $result += "<td>$pv</td>"
      }
      $result += "</tr>"
      $rows++
    }
    else {
      $result += "<table border='1'>"
      foreach ($propset in $proplist.split(",")) {
        $pname = Get-CmxPropName -StringVal $propset -Part 'Realname'
        $xname = Get-CmxPropName -StringVal $propset -Part 'Alias'
        [string]$pv = $row.GetPropertyValue("$pname")
        $npv = Convert-CmxFormat -ClassName $ClassName -PropertyName $pname -Value $pv
        $result += "<tr><td class=`"bggray`">$xname</td><td>$npv</td></tr>"
      }
      $result += "</table>"
    }
  }
  if ($TableMode -eq "multi") {
    $result += "<tr><td class=`"bggray`" colspan=`"$cols`">$rows items returned</td></tr>"
    $result += "</table>"
  }
  return $result
}

<#
.SYNOPSIS
  Get-CmxCmSiteCode
.DESCRIPTION
  Return Configuration Manager SITE CODE from site server query
.PARAMETER ComputerName
  FQDN of Configuration Manager site server
.EXAMPLE
  $sitecode = Get-CmxCmSiteCode -ComputerName "cm1.contoso.com"
#>

function Get-CmxCmSiteCode {
  param (
    [parameter(Mandatory=$True)] [string] $ComputerName,
    [parameter(Mandatory=$True)] $Cred
  )
  $result = Get-WmiObject -Namespace "root\SMS" -ComputerName $ComputerName -Class "__NAMESPACE" -Credential $Cred | 
  Select-Object -ExpandProperty Name
  return $result.replace("site_","")
}

The XML Configuration Parameters File:  queries.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<queries>
 <query type="os" level="1">
 <caption>Computer</caption>
 <space>root\cimv2</space>
 <class>Win32_ComputerSystem</class>
 <props>Name,Domain,Manufacturer,Model,TotalPhysicalMemory=Memory,BootupState,CurrentTimeZone</props>
 <criteria></criteria>
 <mode>single</mode>
 <sort></sort>
 </query>
 <query type="os" level="1">
 <caption>Enclosure</caption>
 <space>root\cimv2</space>
 <class>Win32_SystemEnclosure</class>
 <props>Manufacturer,SerialNumber,ChassisTypes</props>
 <criteria></criteria>
 <mode>single</mode>
 <sort></sort>
 </query>
 <query type="os" level="2">
 <caption>Services</caption>
 <space>root\cimv2</space>
 <class>Win32_Service</class>
 <props>DisplayName,PathName,StartMode,Started,StartName=RunAs</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>DisplayName</sort>
 </query>
 <query type="os" level="2">
 <caption>Operating System</caption>
 <space>root\cimv2</space>
 <class>Win32_OperatingSystem</class>
 <props>Caption,BuildNumber=Build,CSDVersion=ServicePack,InstallDate,OSArchitecture,WindowsDirectory,Organization,EncryptionLevel,DataExecutionPrevention_Available=DEP,DataExecutionPrevention_SupportPolicy=DEPSupport</props>
 <criteria></criteria>
 <mode>single</mode>
 <sort></sort>
 </query>
 <query type="os" level="2">
 <caption>Optional Features</caption>
 <space>root\cimv2</space>
 <class>Win32_OptionalFeature</class>
 <props>Name,InstallState</props>
 <criteria>InstallState=1</criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="2">
 <caption>Installed Software</caption>
 <space>root\cimv2</space>
 <class>Win32_Product</class>
 <props>Name,Vendor,Version,InstallDate,PackageCode</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="3">
 <caption>Installed Updates</caption>
 <space>root\cimv2</space>
 <class>Win32_QuickFixEngineering</class>
 <props>HotFixID,InstalledOn,InstalledBy</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>HotFixID</sort>
 </query>
 <query type="os" level="1">
 <caption>Processor</caption>
 <space>root\cimv2</space>
 <class>Win32_Processor</class>
 <props>Name,MaxClockSpeed=Speed,NumberOfCores=Cores,SocketDesignation=Socket,L2CacheSize,L3CacheSize</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="1">
 <caption>Logical Disks</caption>
 <space>root\cimv2</space>
 <class>Win32_LogicalDisk</class>
 <props>DeviceID=Drive,DriveType=Type,Size,FreeSpace,VolumeName=Label</props>
 <criteria>DriveType=3</criteria>
 <mode>multi</mode>
 <sort>Caption</sort>
 </query>
 <query type="os" level="2">
 <caption>Partitions</caption>
 <space>root\cimv2</space>
 <class>Win32_DiskPartition</class>
 <props>Name,Index,Type,PrimaryPartition=Primary,Size</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="4">
 <caption>Physical Disks</caption>
 <space>root\cimv2</space>
 <class>Win32_DiskDrive</class>
 <props>Index,Name,InterfaceType,Partitions,Size,SectorsPerTrack,TotalSectors</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Index</sort>
 </query>
 <query type="os" level="2">
 <caption>Shares</caption>
 <space>root\cimv2</space>
 <class>Win32_Share</class>
 <props>Name,Path,Description</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="3">
 <caption>Startup Commands</caption>
 <space>root\cimv2</space>
 <class>Win32_StartupCommand</class>
 <props>Name,Location,User,Command</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="3">
 <caption>SCSI Controllers</caption>
 <space>root\cimv2</space>
 <class>Win32_SCSIController</class>
 <props>Name,Index,Manufacturer,DeviceID,DriverName</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="3">
 <caption>Serial Ports</caption>
 <space>root\cimv2</space>
 <class>Win32_SerialPort</class>
 <props>Name,PNPDeviceID,MaxBaudRate,Status,ProviderType</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="3">
 <caption>System Drivers</caption>
 <space>root\cimv2</space>
 <class>Win32_SystemDriver</class>
 <props>DisplayName,Name,PathName,ServiceType</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>DisplayName</sort>
 </query>
 <query type="os" level="2">
 <caption>Local User Accounts</caption>
 <space>root\cimv2</space>
 <class>Win32_UserAccount</class>
 <props>Name,FullName,AccountType,Disabled,PasswordExpires,SID</props>
 <criteria>LocalAccount=True</criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="os" level="3">
 <caption>Local User Profiles</caption>
 <space>root\cimv2</space>
 <class>Win32_UserProfile</class>
 <props>LocalPath,RefCount,LastUseTime,Loaded,SID</props>
 <criteria>RefCount>1</criteria>
 <mode>multi</mode>
 <sort>LocalPath</sort>
 </query>
 <!-- CONFIGURATION MANAGER QUERIES -->
 <query type="cm" level="1">
 <caption>Site Information</caption>
 <class>SMS_Site</class>
 <props>ServerName,SiteCode,SiteName,Version,InstallDir,ReportingSiteCode</props>
 <criteria></criteria>
 <mode>single</mode>
 <sort>ServerName</sort>
 </query>
 <query type="cm" level="1">
 <caption>Site Definition</caption>
 <class>SMS_SCI_SiteDefinition</class>
 <props>SiteCode,SiteName,SiteServerName,SiteServerPlatform=Platform,SQLServerName,SQLDatabaseName</props>
 <criteria></criteria>
 <mode>single</mode>
 <sort></sort>
 </query>
 <query type="cm" level="1">
 <caption>Site System Status Summary</caption>
 <class>SMS_SiteSystemSummarizer</class>
 <props>Role,SiteCode</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Role</sort>
 </query>
 <query type="cm" level="1">
 <caption>Component Status Summary</caption>
 <class>SMS_ComponentSummarizer</class>
 <props>MachineName,ComponentName=Name,SiteCode,Errors,Warnings,Infos,Status</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>MachineName</sort>
 </query>
 <query type="cm" level="1">
 <caption>Discovery Methods</caption>
 <class>SMS_SIIB_Configuration</class>
 <props>ConfigurationName=Name,Flags</props>
 <criteria>Type='Discovery Method'</criteria>
 <mode>multi</mode>
 <sort>ConfigurationName</sort>
 </query>
 <query type="cm" level="1">
 <caption>AD Forest Discovery</caption>
 <class>SMS_ADForest</class>
 <props>EnableDiscovery=Enabled,ForestFQDN=Forest,PublishingPath,PublishingStatus=Published</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>ForestFQDN</sort>
 </query>
 <query type="cm" level="2">
 <caption>Site Boundaries</caption>
 <class>SMS_Boundary</class>
 <props>DisplayName,BoundaryType,DefaultSiteCode,SiteSystems,Value</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>ForestFQDN</sort>
 </query>
 <query type="cm" level="2">
 <caption>Site Boundary Groups</caption>
 <class>SMS_BoundaryGroup</class>
 <props>Name,GroupID,DefaultSiteCode,SiteSystemCount,MemberCount,Description</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="2">
 <caption>Client Settings Default</caption>
 <class>SMS_ClientSettingsDefault</class>
 <props>Name,Enabled,Priority,Description</props>
 <criteria></criteria>
 <mode>single</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="2">
 <caption>Client Components</caption>
 <class>SMS_SCI_ClientComp</class>
 <props>ClientComponentName=Component,ItemName=Description,Flags</props>
 <criteria>ItemType='Client Component'</criteria>
 <mode>multi</mode>
 <sort>ClientComponentName</sort>
 </query>
 <query type="cm" level="2">
 <caption>AD Sites</caption>
 <class>SMS_ADSite</class>
 <props>ADSiteName=Name,ADSiteDescription=Description</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>ADSiteName</sort>
 </query>
 <query type="cm" level="2">
 <caption>AD Subnets</caption>
 <class>SMS_ADSubnet</class>
 <props>ADSubnetName=Name,ADSubnetLocation</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>ADSubnetName</sort>
 </query>
 <query type="cm" level="2">
 <caption>Collections</caption>
 <class>SMS_Collection</class>
 <props>Name,CollectionID,CollectionType,MemberCount,LimitToCollectionName=LimitedTo</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="3">
 <caption>Applications</caption>
 <class>SMS_Application</class>
 <props>LocalizedDisplayName=Name,DateCreated,IsDeployed,NumberOfDevicesWithApp=InstDevs,NumberOfUsersWithApp=InstUsers</props>
 <criteria>CIType_ID=10</criteria>
 <mode>multi</mode>
 <sort>LocalizedDisplayName</sort>
 </query>
 <query type="cm" level="2">
 <caption>Packages</caption>
 <class>SMS_Package</class>
 <props>Name,Manufacturer,Version,PackageID,PackageType,PackageSize=Size,PkgSourcePath=SourcePath</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="3">
 <caption>Advertisements</caption>
 <class>SMS_Advertisement</class>
 <props>AdvertisementName=Name,AdvertisementID=AdvID,CollectionID,PackageID,SourceSite</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>AdvertisementName</sort>
 </query>
 <query type="cm" level="2">
 <caption>Deployment Summary</caption>
 <class>SMS_DeploymentSummary</class>
 <props>ApplicationName,CollectionID,CollectionName,FeatureType,NumberTargeted=Targeted,NumberInProgress=InProgress,NumberSuccess=Success,NumberErrors=Failed,NumberOther=Other,NumberUnknown=Unknown</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>ApplicationName</sort>
 </query>
 <query type="cm" level="3">
 <caption>Image Packages</caption>
 <class>SMS_ImagePackage</class>
 <props>Name,PackageID,PackageSize,Language</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="4">
 <caption>Task Sequences</caption>
 <class>SMS_TaskSequencePackage</class>
 <props>Name,Description,PackageID,BootImageID,ReferencesCount=Refs,SourceDate=Date</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="4">
 <caption>Task Sequence References</caption>
 <class>SMS_TaskSequenceReferencesInfo</class>
 <props>ReferenceName=Name,ReferenceVersion=Version,PackageID</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>ReferenceName</sort>
 </query>
 <query type="cm" level="4">
 <caption>OS Deployment Kits</caption>
 <class>SMS_OSDeploymentKitInstalledVersion</class>
 <props>DeploymentKitVersion=Version,NetBiosName,FQDN</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>DeploymentKitVersion</sort>
 </query>
 <query type="cm" level="4">
 <caption>OS Deployment Configurations</caption>
 <class>SMS_OSDeploymentConfig</class>
 <props>DeploymentPropertyName,DeploymentPropertyValue,DeploymentKitVersion</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>DeploymentPropertyName</sort>
 </query>
 <query type="cm" level="4">
 <caption>Queries</caption>
 <class>SMS_Query</class>
 <props>Name,QueryID,TargetClassName,Expression</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="4">
 <caption>PXE Certificates</caption>
 <class>SMS_PXECertificateInfo</class>
 <props>PXEServerName,Type,KeyType,IsApproved,IsBlocked,ValidFrom,ValidUntil</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>PXEServerName</sort>
 </query>
 <query type="cm" level="4">
 <caption>Endpoint Protection Policies</caption>
 <class>SMS_AntimalwareSettings</class>
 <props>Name,Description,AssignmentCount,Priority,DateModified,LastModifiedBy</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>Name</sort>
 </query>
 <query type="cm" level="2">
 <caption>Intune Account</caption>
 <class>SMS_IntuneAccountInfo</class>
 <props>IntuneAccountID,LastUpdateTime</props>
 <criteria></criteria>
 <mode>single</mode>
 <sort></sort>
 </query>
 <query type="cm" level="3">
 <caption>Site Maintenance Tasks</caption>
 <class>SMS_SCI_SQLTask</class>
 <props>TaskName,Enabled,ItemName,SiteCode,DaysOfWeek,BeginTime,DeviceName</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>TaskName</sort>
 </query>
 <query type="cm" level="3">
 <caption>User Roles</caption>
 <class>SMS_Role</class>
 <props>RoleName=Name,RoleDescription=Description,IsBuiltIn,NumberOfAdmins=Members,SourceSite</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>RoleName</sort>
 </query>
 <query type="cm" level="3">
 <caption>Replication Link Status</caption>
 <class>SMS_ReplicationLinkStatus</class>
 <props>ParentSite,ChildSite,ParentLastSent,ParentLastReceived,ChildLastSent,ChildLastReceived,InitializationStatus=InitStatus</props>
 <criteria></criteria>
 <mode>multi</mode>
 <sort>ParentSite</sort>
 </query>
</queries>

Summary

The Queries.xml file allows you to add more classes, and for the “os” items, you can customize the WMI namespaces for additional flexibility.  The “cm” section is somewhat hard-coded by virtue of the “root\SMS\site_XXX” site code inclusion.  In any case, give it a try and let me know what you think?

Advertisements

2 thoughts on “Yet Another SCCM PowerShell Inventory Script

  1. $cols = $labels.split(“,”).lengtheach ($row in $wmiData) {

    I think you’re mixing javascript with PowerShell…. or at least, I’m not having any luck running it?

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s