File Inventory via Configuration Items rather than Software Inventory

It’s no secret that I’m not a fan of using Software Inventory (SWINV). So when I recently got a request to report on whether certain files existed on machines I decided to do something a little different.

I was asked to find out if a list of 9 dlls existed within a specific folder on machines. Normally you’d create a rule for each of these (or one generic rule) in SWINV, wait for machines to get the new policy and run SWINV and send the information back to the site. Instead, I chose to write a PowerShell script that would return the information in one JSON output, and deploy that script as a Configuration Item/Baseline (CI/BL).

This way I could deploy the CI/BL and have the machines return info much faster than waiting for the SWINV cycle. Plus, the CI/BL seems to be more reliable than SWINV.

There are a number of ways I could’ve gone about writing the script. I could’ve gotten every “*.dll” that existed in the given folder. But instead I decided to actually check the folder path for each specific dll name. (Note: I have changed or hidden the original dll names to a more Microsoft friendly company name – Contoso. 🙂 ) Here’s the sample PS:

$ContosoPath = "$env:ProgramFiles\Contoso\ContosoApplicationName\ExtensionPacks\Contoso_Extension_Pack";
if ((Test-Path -Path $ContosoPath) -eq $true) {
    $ContosDlls = @("ContosPluginCrypt.dll","VContos.dll","VContosUsbWebcam.dll","VContosUsbCardReader.dll","VContosMain.dll","VContosPuelMain.dll","VContosNvme.dll","VContosWebcam.dll","VContosEhci.dll");
    $Json = New-Object -TypeName System.Collections.Hashtable;
    foreach ($Dll in $ContosDlls) {
        $DllExistence = Get-ChildItem -Path $ContosoPath -File -Recurse -Filter $Dll -Name;
        if ($DllExistence -ne $null) {
            $DllExistence = $true;
        }
        else {
            $DllExistence = $false;
        }
        $Json.Add($Dll,$DllExistence);
    }
    
    return (ConvertTo-Json -InputObject $Json -Compress);
}
else {
    return 0;
}

As you can see, if the folder doesn’t exist I simply return a “0”, but if it does exist I start checking for each of the dlls. It wasn’t clear if the dlls would exist in the main folder or if they could exist in any folder underneath the main path so I used the “Recurse” flag to check everything. I save the information for each dll as a key/value pair in a hashtable which makes it easy to convert to JSON. An example of the JSON that gets created is:

{
    "VContosWebcam.dll":  true,
    "VContosMain.dll":  true,
    "VContosUsbWebcam.dll":  true,
    "VContos.dll":  true,
    "VContosUsbCardReader.dll":  false,
    "ContosPluginCrypt.dll":  true,
    "VContosNvme.dll":  true,
    "VContosEhci.dll":  true,
    "VContosPuelMain.dll":  true
}

I’m not really interested in knowing the compliance of this CI/BL, what I’m really interested in is knowing which machines didn’t return a “0” and then to see which dlls exist for those machines. As the machines start running the script and reporting back, the data can be found in the view “v_CIComplianceStatusDetail”; for example:

CI detail in SQL view

And, with SQL’s handy OPENJSON function, it’s quite simple to write a query that ‘shreds’ the information into a nice handy table. (Perhaps I’ll do a blog post on OPENJSON sometime if it seems necessary…). It then becomes pretty easy to determine which machines or how many machines have these dlls installed; or, in our example, determine if “Contoso” extension packs are installed. And, we got the info relatively easily and quickly. Here’s the SQL code shredding the JSON:

SELECT  ccs.ResourceID
       ,jsn.*
  FROM dbo.v_CIComplianceStatusDetail ccs WITH (NOLOCK)
       CROSS APPLY OPENJSON(ccs.CurrentValue) WITH ( VContosWebcam bit '$."VContosWebcam.dll"'
                                                    ,VContosMain bit '$."VContosMain.dll"'
                                                    ,VContosUsbWebcam bit '$."VContosUsbWebcam.dll"'
                                                    ,VContos bit '$."VContos.dll"'
                                                    ,VContosUsbCardReader bit '$."VContosUsbCardReader.dll"'
                                                    ,ContosPluginCrypt bit '$."ContosPluginCrypt.dll"'
                                                    ,VContosNvme bit '$."VContosNvme.dll"'
                                                    ,VContosEhci bit '$."VContosEhci.dll"'
                                                    ,VContosPuelMain bit '$."VContosPuelMain.dll"'
                                                    ) jsn
 WHERE ccs.CI_ID = 1234567 -- just plug in your CI_ID for the Configuration Item here
   AND ccs.CurrentValue != N'0';

And, here’s a sample of the output (“0” = false or the dll doesn’t exist in the folder; “1” = true or the dll does exist in the folder):

CI detail JSON Shredded

There you have it, another way to make use of Configuration Items/Baselines to answer specific questions quickly and easily…without using Software Inventory. 🙂

Advertisements

2 thoughts on “File Inventory via Configuration Items rather than Software Inventory

  1. This may be HUGE for me. I’ve been looking st the overhead of SINV lately and discovered that it’s really not needed for Software Metering as I thought it used to be.

    We Meter hundreds of apps so, ad you can imagine, our SINV rules are just stupid at this point.

    Your solution looks FAR more efficient and elegant while still retaining all we need, I think.

    Question though… if we need to know the meta data of the files (description, oublisher, version, etc), is this also obtained through your method or is it a binary ‘this machine has the file(s), this one doesnt’? That’s how I read it as I quickly skimmed the code..

    Thanks again for this blog (new and old one). It’s helped me often!

    Like

    1. Thanks GregD! Yes, this specific script is just a “this machine has this file(s)” type of script. However, if you needed additional information from a file you could add that to the script – just store that information in the JSON and it would have what you need. Some of that information could be captured with Get-ItemProperty but you’d have to look into what is there and how to get everything you’re needing.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

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

Google photo

You are commenting using your Google 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 )

Connecting to %s