...building hybrid clouds that can support any device from anywhere
Welcome to Part 2 in my PowerShell Desired State Configuration blog series. In Part 1 last week, I pulled together a number of online resources that helped me when getting up to speed on DSC. This week, I’d like to share a process for authoring resources that has saved me a lot of time.
Go To Example Script
This approach is specifically intended for the scenario where native cmdlets, or cmdlets that shipped from the developer of the software, already exist.
I’m not declaring this a “best practice” or the perfect method of authoring, I’m saying this is a process that works for me and has saved me a lot of time, so it might work for you too. One of the core concepts is splatting parameter values in to native cmdlets.
I actually didn’t come up with it as an approach to DSC. If you look at the DSC Resource Kit contribution xNetworking, the concept is there in xIPAddress and xDNSServerAddress. Those resources actually ignited my thinking. The same approach is applied in xSmbShare, xRemoteDesktopSessionHost, and probably others.
In addition to splatting parameters, here is the basic storyline I follow over and over again:
I always start by looking at New and/or Set. Specifically, I like to run Show-Command and look at what parameters are there that help me accomplish what I have in mind.
I’ve taken *-DNSClientServerAddress and made it a boilerplate example template, included at the bottom of this post. I picked a scenario that already has a published resource on purpose so that this would be looked at as an example, not as a newly published resource. I’ve added a lot of notes throughout so that you don’t have to come back and re-read a long blog post to figure out what I was thinking through each section. Like any DSC Resource, it has Get, Set, and Test, but let’s take a look at the anatomy a little closer.
I have taken snips of each script section below as reference to my explanations. Click each thumbnail to gain additional context.
The notes section explains what I have in mind and calls out some special cases to watch out for. Example, if you have a cmdlet that accepts an object type as input, you may have to pass in a string value that you use to go get the object and then pass the object on to the native cmdlets. That would make it a two step process.
The Set function is second in the script but I always start with Set. You’ll see I’ve bound the function as a region. That’s so I can include comments and examples for testing but easily collapse the whole thing out of my way if I’m working between Get and Test in ISE. For this section, I’m literally just running the native Set cmdlet and then splatting in the parameters. Splatting, is a simple method of taking a hash table of values and passing it as arguments to a command. Isn’t it convenient, PSBoundParameters is automatically generated inside a function so I don’t have to create anything.
For the Get function I just run the native Get cmdlet, remove Verbose and Debug from the function parameters, and then run a foreach loop to build a hash table. If you have a lot of parameters this can save a lot of typing. Important – this only works perfectly when the parameters are the same for Get and Set. If your Get function has fewer parameters it usually works out because the example is pulling only what you need out of what is returned by the Get cmdlet. If you need to return more values than the cmdlet, possibly calling multiple cmdlets, you could apply this more than once or add static entries. In either case you just append $out using += and then return $out.
And finally the Test function. Again if everything happens to have a common set of parameters (Nirvana), I literally don’t have to touch this section at all. The way this sample works is to run the Get function and compare the output against the values from the Test function parameters. The Set and Test functions share a common set of parameters so this validates everything that can be set. If the Get function accepts a subset of parameters then I modify the line starting with $Get to pass those as arguments one by one.
Notice that at the bottom of each section I include a commented out test for every function. This is to make it easier on me when doing test and validation, especially if I haven’t looked at the module in a while.
A few enhancements I sometimes use:
I’ll wrap up here and paste the boilerplate example at the bottom so you don’t have to expect additional reading after the large script sample block.
I’ve had a number of people ask me ‘'What’s the point of creating a DSC resource, when you already have cmdlets. Why not just write a script?” Well, I’m not going to get on much of a soapbox but here are a few bullets to ponder.
Thanks and stay tuned to Building Clouds Blog!
Great post! Looking forward to more.
Awesome post!! Would definitely help me save ton of time as well :)