Documentation as Code : Exporting the contents of DSC MOF files to Excel

One of the greatest benefits of PowerShell DSC (and other Configuration Management tools/platforms) is the declarative syntax (as opposed to imperative scripting). Sure, a DSC configuration can contain some logic, using loops and conditional statements, but we don’t need to care about handling errors or checking if something is already present. All this (and the large majority of the logic) is handled within the resource, so we just need to describe the end result, the “Desired State”.

So all the settings and information that a configuration is made of are stored in a very simple (and pretty much human-readable) syntax, like :

Node $AllNodes.NodeName
    {
        cWindowsErrorReporting Disabled
        {
            State = "Disabled"
        }
    }

 
This allows us to use this “code” (for lack of a better word) as documentation in a way that wouldn’t be possible or practical with imperative code. For this purpose, we could use DSC configurations, or DSC configuration data files if all the configuration data is stored separately. But the best files for that would probably be the MOF files for 2 reasons :

  • Even if some settings are in different files, we can be sure that all the settings for a given node is in a single MOF file (the exception being partial configurations)
  • Even if the DSC configuration contains complex logic, there is no need to understand or parse this logic to get the end result. All this has been done for us when the MOF file has been generated

Now, imagine you have all your MOF files stored in a directory structure like this :

PS C:\> tree C:\DSCConfigs /F
Folder PATH listing for volume OS
C:\DSCCONFIGS
├───Customer A
│   ├───Dev
│   │       Server1.mof
│   │       Server2.mof
│   │
│   ├───Prod
│   │       Server1.mof
│   │       Server2.mof
│   │
│   └───QA
│           Server1.mof
│           Server2.mof
│
├───Customer B
│   ├───Dev
│   │       Server1.mof
│   │       Server2.mof
│   │
│   ├───Prod
│   │       Server1.mof
│   │       Server2.mof
│   │
│   └───QA
│           Server1.mof
│           Server2.mof
│
└───Customer C
    ├───Dev
    │       Server1.mof
    │       Server2.mof
    │
    ├───Prod
    │       Server1.mof
    │       Server2.mof
    │
    └───QA
            Server1.mof
            Server2.mof

You most likely have much more than 2 servers per environment, so there can easily be a large number a MOF files.
Then, imagine your boss tells you : “I need all the configuration settings, for all customers, all environments and all servers in an Excel spreadsheet to sort and group the data easily and to find out the differences between Dev and QA, and between QA and Prod”.

If you are like me, you may not quite understand bosses’ uncanny obsession with Excel but this definitely sounds like something useful and an interesting challenge. So, let’s do it.

We’ll divide this in 3 broad steps :

  • Converting the contents of MOF files to PowerShell objects
  • Exporting the resulting PowerShell objects to a CSV file
  • Processing the data using PowerShell and/or Excel

Converting the contents of MOF files to PowerShell objects

This is by far the most tricky part.
Fortunately, I wrote a function, called ConvertFrom-DscMof, which does exactly that. We won’t go into much details about how it works, but you can have a look at the code here.

Basically, it parses one or more MOF files and it outputs an object for each resource instance contained in the MOF file(s). All the properties of a given resource instance become properties of the corresponding object, plus a few properties related to the MOF file.

Here is an example with a very simple MOF file :

ConvertFrom-DscMofExample
 
And here is an example with all the properties of a single resource instance :

ConvertFrom-DscMofSingle
 

Exporting the resulting PowerShell objects to a CSV file

As we have the ability to get DSC configuration information in the form of PowerShell objects, it is now very easy to export all this information as CSV. But there’s a catch : different resources have different parameters, for example the Registry resource has the ValueName and ValueData parameters and the xTimeZone resource has a TimeZone parameter.

So the resulting resource instances objects will have ValueName and ValueData properties if they are an instance of the Registry resource and a TimeZone property if they are an instance of the xTimeZone resource. Even for a given resource, some parameters are optional and they will end up in the properties of the resulting PowerShell object only if they were explicitly specified in the configuration.

The problem is that Export-Csv doesn’t handle intelligently objects with different properties, it will just create the columns from the properties of the first object in the collection and apply that to all objects, even for objects which have different properties.

But, we can rely on the “ResourceID” property of each resource instance because it uniquely identify the resource instance. Also, it contains the name we gave to the resource block in the DSC configuration, which should be a nice meaningful name, right ?
Yeah, this is where “Documentation as code” meets “self-documenting code” : they are both important and very much complementary. To get an idea of what the values of ResourceID look like, refer back to the first screenshot.

Below, we can see how to export only the properties we need, and only the properties that we know will be present for all resource instances :


Get-ChildItem C:\MOFs\ -File -Filter "*.mof" -Recurse |
ConvertFrom-DscMof |
Select-Object -Property "MOF file Path","MOF Generation Date","Target Node","Resource ID","DSC Configuration Info","DSC Resource Module" |
Export-Csv -Path 'C:\DSCConfig Data\AllDSCConfigs.csv' -NoTypeInformation

 

Processing the data using PowerShell and/or Excel

The resulting CSV file can be readily opened and processed by Excel (or equivalent applications) :

CSVFileInExcel
 
Now, we have all the power of Excel at our fingertips, we can sort, filter, group all this data however we want.

Now, here is a very typical scenario : the Dev guys have tested their new build and it worked smoothly in their environment. However, the QA guys say that the same build is failing miserably in their environment. The first question which should come to mind is : “What is the difference between the Dev and QA environments ?

If all the configuration of these environments is done with PowerShell DSC, the ConvertFrom-DscMof function can be a great help to answer that very question :

C:\> $CustomerCDev = Get-ChildItem -File -Filter '*.mof' -Recurse 'C:\MOFs\Customer C\Dev\' |
ConvertFrom-DscMof
C:\> $CustomerCQA = Get-ChildItem -File -Filter '*.mof' -Recurse 'C:\MOFs\Customer C\QA\' |
ConvertFrom-DscMof
C:\> Compare-Object -ReferenceObject $CustomerCDev -DifferenceObject $CustomerCQA -Property 'Target Node','Resource ID'

Target Node Resource ID                    SideIndicator
----------- -----------                    -------------
Server1     [xRemoteFile]RabbitMQInstaller <=
Server1     [Package]RabbitMQ              <=

 
Oops, we forgot to install RabbitMQ on Server1 ! No wonder it’s not working in QA.
But now, there is hope. We, forgetful and naturally flawed human beings, can rely on this documentation automation to tell us how things really are.

So, as we have seen, Infrastructure-as-code (PowerShell DSC in this case) can be a nice stepping-stone for an infrastructure documentation.
What is the number 1 problem for any infrastructure/configuration documentation ?
Keeping it up-to-date. This can help generate dynamically the documentation, which means this documentation can be kept up-to-date pretty easily without any human intervention.

Leave a Reply

Your email address will not be published. Required fields are marked *