DSC: Combining class and MOF-based resources in one module

I had the need to add a class-based resource to an existing module that only contained MOF resources. Initially, I dropped the .psd1 and .psm1 files into the module’s DSCResources folder and updated the root .psd1 file. Using Get-DSCResource -Name ModuleName the new class resource was visible. I created a new configuration, to use the resource which compiled without issue, however on running it with Start-DSCResource I got the lovely error:

When browsing to C:\Windows\system32\config\systemprofile\AppData\Local\dsc\, I could see the file SqlServerDsc.10.0.cSQLServerTraceFlag.schema.mof had been created, however, it’s the wrong name.

After a lot of messing around with the new using key word, I started to look at the cmdlet that produces the incorrectly named file Start-DscConfiguration, which is part of the built-in PSDesiredStateConfiguration module. Looking at its .psd1 file, I noticed in the NestedModules = @() section the entry 'DSCClassResources\WindowsPackageCab\WindowsPackageCab.psd1' and sure enough the resource had the folder PSDesiredStateConfiguration\DSCClassResources.

Back to my module, I created the folder `ModuleName\DSCClassResources, moved the class-based resource into it, tried the configuration again and this time, not only did it compile, it also ran.

In this case, I was adding a community class resource to the SqlServerDsc resource. Probably not best practice, but I couldn’t wait for the developer to finish testing and for MS to commit it to the master branch.

Steps

The steps are:

  1. Download cSqlServerTraceFlag. Extract ZIP and rename to
  2. cSqlServerTraceFlag Create the folder
  3. “%ProgramFiles%\WindowsPowerShell\Modules\SqlServerDsc\DSCClassResources”
  4. Drop the folder (cSqlServerTraceFlag) into “%ProgramFiles%\WindowsPowerShell\Modules\SqlServerDsc\DSCClassResources”
  5. Edit .\Modules\SqlServerDsc\SQLServerDsc.psd1, adding:
    • NestedModules = @(‘DSCResources\cSQLServerTraceFlag\cSQLServerTraceFlag.psm1’)
    • DscResourcesToExport = @(‘cSQLServerTraceFlag’)

Testing

The configuration I used to test:

Update 1

I’ve discovered a little more is involved when there are helper functions in the mix. Like a good little wannabe developer, I encapsulate my functions. i.e each function is in its own .PS1 file.
Best practice dictates, in *.PSD1 files, we shouldn’t use FunctionsToExport = '*'. Instead we should explicitly name the functions. This is needed for the “AutoLoad” function feature to work anyway:

So my resource file structure looks like:

When I moved aClassResource from ..Modules to ..Modules\Demo, I did the changes to Demo.psd1 as documented above, however aClassResource was not picked up by Get-DscResource -Module Demo until I set FunctionsToExport = '*', however this really slowed down Intellisence, compilation and execution. I recalled reading this post, whilst troubleshoot ordinary PS modules in the past. I looked it up again, and tried “Ewan Middleton’s” advice:

Try removing the .psm1 suffix from each of the Nested Modules you have listed, so you’ll have NestedModules = @(‘Mod1′,’Mod2’). I was experiencing exactly the scenario as you until I did this and now both nested modules autoload as expected and I can see all exported functions from both when using Get-Module. This is even after restarting ISE and deleting CommandAnalysis.

In Demo.psd1, I changed NestedModules = @('DSCResources\aClassResource\aClassResource.psm1') to NestedModules = @('DSCResources\aClassResource\aClassResource').
In Demo.psd1, I left FunctionsToExport = @('Get-Something','Invoke-SomethingElse'.'Write-LetterToJohn') unchanged.
In aClassResource.psm1, I changed FunctionsToExport = '*' to FunctionsToExport = @('Get-RegistryKey','Add-RegistryKey'.'Remove-RegistryKey').

Running Get-DscResource -Module Demo works, and I can compile and execute the module.

I’m sure there will be more changes along the way and sticking to the principle of ‘Encapsulation’, I should refactor aClassResourceHelper.psm1 functions into their own .ps1 files.

Please feel free to leave a comment...