Managing PowerShell DSC with Puppet
Editor’s note: This is one in a series of posts about using Puppet to automate your Windows servers. Follow us on social media or subscribe to our our RSS feed to be notified when the next post is released.
While you can use DSC on its own, it's much better with Puppet. In this blog post we’ll look at several reasons Puppet and PowerShell DSC can work together to enable you to do more.
Puppet enables you to use your skills to do more. Puppet DSL is very similar to PowerShell DSC syntax, which lets you get up and running quickly. You can migrate a PowerShell DSC configuration script to a Puppet manifest with just a few text edits. Overall there is less code than when you use Puppet and DSC together.
With DSC and Puppet, you can get all the advantages of both tools. There are thousands of resources from Puppet, Microsoft and the community so you can handle multiple platforms across your entire environment.
Puppet provides rich management capabilities that can layer on top of DSC, including node classification, status of nodes, global-based access control and more. Tracking and reporting change becomes easier with Puppet — and reporting is a must for any company that has to do any kind of compliance auditing.
Use the skills you have to do more
Doing more with less sounds like a cliche, but it’s a fact of life for any sysadmin or developer. Time and resource constraints necessitate flexibility and resourcefulness. With Puppet, you can take your existing PowerShell DSC skills and knowledge and apply them directly to fixing the problem at hand without having to learn everything up front. As you do more, you can delve deeper, but you can get going quickly with Puppet.
Often times, a Puppet manifest has less code to write than a PowerShell DSC configuration script.
A few examples:
Here’s a PowerShell DSC configuration script on the left and a Puppet manifest on the right. It’s essentially compressing a log directory and ensuring that a file is present on the system with specific text inside it. If you're new to Puppet, but know PowerShell, you'll be right at home using the Puppet DSC module. Even if you're not familiar with PowerShell, it's so human-readable that you can see what’s going on right away.
DSC works a lot like Puppet in many ways. It's declarative, uses a similar syntax and similar terminology. Right away, you can see that there are only a few syntactical differences you need to account for when migrating to a Puppet manifest. You have to add a
dsc_ prefix to all resource declarations and to all parameters, the equal signs turn into hashrockets and commas are added at the end of each line.
These are simple, short changes that make sense. The syntax is similar, so there isn't any cognitive dissonance switching from a PowerShell DSC resource to a Puppet module declaration. You’ll notice there's less to write using Puppet — no configuration blocks to add, no DSC Resource module import declarations to keep track of, just the individual components.
All PowerShell DSC types are supported in Puppet, including base types like integers, complex types like PS credentials and even custom bindings.
Moving your PowerShell DSC to Puppet is just the beginning. You can do much more when you use PowerShell and Puppet together.
DSC and Puppet: best of both worlds
Every developer or system architect reuses existing code. That's why the Puppet DSC module enables you to use the 200-plus PowerShell DSC Resources that have already been released and tested by the PowerShell community. Some of these resources cover scenarios not yet addressed by Puppet.
Like Lego pieces, you can mix and match the DSC resources and Puppet modules to address any situation you encounter. And when you come to something that DSC can't do or a platform it doesn't support, you can tap 4,000-plus Puppet modules. Puppet supports almost all operating systems and platforms under the sun — Windows, Linux, network devices, storage arrays and more.
DSC is a powerful platform, but it’s a new technology. Like many new products, it needs to choose which features to implement first. This is not a bad thing; it is focusing on delivering value first and getting it right, then filling in the edges as time goes on.
Many PowerShell community members wanted the ability to restart a service when its configuration file has changed. Most currently work around it by using the script DSC resource. It's a good workaround, but you have to do all the work yourself to ensure the script DSC resource is idempotent, i.e., that it only changes the state of the system if it's not in the desired state. It's extra work for you and it’s not portable. You have to modify it for every individual service you handle. Instead, we can use Puppet with DSC to solve the problem.
In our scenario, we need to update the configuration file after the product is installed, which requires us to restart the service. We model this by first declaring a PowerShell DSC resource that will handle installing the MSI for us. Then we'll use the Puppet file module to ensure that the file is present on the target node and continues to use the text that we want. Lastly, we'll set the Puppet service module to ensure that the service is running.
Notice that the line in the file declaration says it'll notify the service module. This means that if the file module changes anything, it’ll send a notification to Puppet to tell the service module to perform the refresh. The service module doesn't know anything about the config file or when it changes. It just receives the notification from Puppet that it needs to refresh or restart. These change notifications make Puppet a really powerful way to model and control change in your environment.
When we run that example, Puppet will start up, run, process the file, create the catalog, make the dependencies and examine the system to see that it needs to perform a certain set of operations.
Puppet will install the product, start the service, set the configuration file and then restart the service.
Now that we have a simple example of how Puppet and DSC can work together, let’s move onto a more complicated example by deploying an ASP.NET website.
This example is more complicated, because there are several software modules needed for the ASP.net website to run, as well as configuration settings that need to be set. We're using DSC along with Puppet because the IIS DSC resource has some features that we don't have in Puppet yet. And it'll let us get the website up and running quickly. (To learn how to set up an ASP.net website, take a look at our deep-dive DSC blog post here.)
Here are two script files. On the left is our existing PowerShell DSC configuration file, on the right is the Puppet manifest that we ported from the DSC configuration file. When we move to the Puppet manifest, we immediately see a reduction in code ceremony that results in less code written, and less to think about when writing it.
We immediately see several benefits after writing the Puppet manifest. We don't have to worry about listing the DSC Resources module imports. We don't have to worry about having a correct configuration block declaration.
We can describe the dependencies between the resources using the simple dependency symbol, which results in less to write, as well as making it easier to move around resources without having to update the syntax. In the Puppet manifest, global parameter defaults reduce the amount of repetitive code you have to write.
Even in a complicated example, the syntax is nearly one to one. Someone looking at a PowerShell DSC configuration can look at the Puppet manifest file and can immediately understand what's going on.
Here the Puppet run has finished — and it did it in 18 seconds. Here’s what was installed the website:
It’s a functioning ASP.NET website.
Reporting with Puppet and DSC
Change reporting is a must for any company that has to comply with auditing. Being able to pinpoint when something has been successfully changed is a huge step toward gaining true control over your environment.
Seeing changes across your environment in an easily accessible manner reduces the amount of time spent verifying the change. You don't have to manually check the state because the data is already collected for you. Historical reporting is equally important, because knowing when something broke is just as important as knowing what broke. If you're able to find out when the change happened, correlation to other events becomes easier and reduces the amount of time spent troubleshooting.
PowerShell DSC does not keep historical data on changes performed, but it does provide some ways for you to find out what changed manually. PowerShell shows the status of the whole operation, not on a resource-by-resource basis. This provides a good indication of the state of the last run, but you can't find out what changed over time. In PowerShell 4, this is accomplished by using the event logs and searching for the last run result. In PowerShell 5, you can use the Get-Dsconfiguration status command to get the same information.
PowerShell results are only available on the target node, unless a DSC pull server is set up. The DSC Pull Server can store the last result for all the target nodes configured to point to it. But it still requires a manual call to get to the information. You can script these calls to generate reports, but it’s not built in.
Puppet can extend DSC by providing historical change tracking and reporting. Configuration results and history are available on the target nodes, as well as in the Puppet server web UI. The web UI provides a single interface that shows the status of your environment down to the individual servers. It even shows resource-by-resource change. It shows the result of each DSC resource execution and a log of the execution as well. Puppet keeps all of these reports. This lets you investigate over time how things change in your environment.
But how do you find errors that are occurring during a DSC configuration run? You can easily search the event log. It can either be done manually with the event viewer or using the DSC diagnostics module commands Get DSC Operation and Trace DSC Operation. They can be run either locally or remotely. Get-DSC Operation lists the statuses for the last few DSC operation runs and returns an object that has information about the time it was created, whether the run was successful or not and all the events generated by that run.
You can use this command to find the specific DSC job that created the condition you want to investigate. Trace DSC Operation takes the job ID or sequence ID from the Get DSC Operation commandment as parameters and delivers a readable list of events that were generated by the respective operation.
By default, Trace DSC Operation will list all the events generated. This command returns an object that contains the properties, like the event type, event message, and event creation. The results of this command are what you use to figure out which part of the DSC configuration is failing and what the root cause is. In Puppet, it's a little different experience.
With Puppet, errors are put up front. And they're easy to diagnose, because they're in the same UI used to finds errors in DSC. These are the same messages you would see in the DSC, in the event log, or in the PowerShell console. But instead, they're viewable inside the Puppet server UI. That means that they're able to be exported in reports, investigated at later times, or examined among servers in your environment.
Puppet automatically logs the results of all of the actions taken either by Puppet or DSC. So you can review exactly what happened without having to go to the target node or run commands manually yourself. This is a huge time saver when you're on the line to figure out why something went wrong. It's just a few clicks compared to several minutes running commands and searching through events.
James Pogran is a software engineer at Puppet.
- You can learn a lot more about how to manage Windows environments with Puppet in our Windows webinars.