Using Desired State Configuration and Chef to deploy System Center

Doctor Scripto

Summary: Learn how to use Chef and DSC in Windows PowerShell to deploy System Center in this guest blog post by Jason Morgan.

Ed Wilson, here. Today I have a guest blog post by Jason Morgan in which he will talk about using Desired State Configuration (DSC) and Chef to deploy System Center. Welcome back, Jason…

Hello again. Today I’m writing to analyze the deployment of System Center by using Desired State Configuration and Chef. I’ve been using Chef heavily for the last six months because I decided that using DSC to run my System Center deployments was a too heavy lift on its own. Adding Chef has allowed me to run my System Center builds from my local lab through my test, UAT, and production environments with a single repository.

Likewise, DSC has provided me with a simple and common interface for dealing with Windows Server, which I’ve found greatly expands the administrative surface for Chef (where those resources are somewhat limited).

DSC and System Center

I’ve been taking advantage of the resources provided by Microsoft to deploy some common System Center components: SCOM, SMA, and Service Manager. In this regard, xSCOM and xSCSMA do a pretty good job for SCOM and SMA, but there is no such resource for Service Manager.

For all the System Center components I use the Group, User, Package, and WindowsFeature resources to configure the prerequisites. You can write loops in Chef to handle adding these prerequisites. The resources are called in almost the same way as in PowerShell. Here’s a quick example:

[‘NLB’,’RSAT-NLB’].each do |feature|

 dsc_resource feature do

            resource :WindowsFeature

            property :Name, feature

            property :Ensure, ‘Present’



Here I take an array of two strings, NLB and RSAT-NLB, and I assign them to a variable named Feature and loop through the WindowsFeature DSC resource.

Chef lets you store information such as users and passwords in searchable repositories called “data bags.” You can encrypt data bag items and make use of Chef’s own security system to decrypt data bag items on the individual nodes. This makes the distribution of account information especially simple. Here’s an example of searching through the items in the user’s collection with a name matching myapp and adding them to the admin group:

search(‘users’,”id:*myapp*”).each do |admin|

            dsc_resource “Administrator #{admin[‘id’]}” do

            resource :Group

            property :GroupName, ‘Administrators’

            property :Ensure, ‘Present’

            property :MembersToInclude, [“#{node[‘serverBase’][‘netbiosName’]}\\#{admin[‘id’]}”]

            property :Credential, ps_credential(“#{node[‘serverBase’][‘netbiosName’]}\\#{install[‘id’]}”,install[‘password’])



You have the option to store non-standard resources with your cookbooks if they are not too large. Personally, I archive any non-standard resources along with the actual binaries I need for the installations. I maintain the archive within a web server built for each environment. Here is an example of using a native Chef resource, remote_file, to download the WMF5 update and store it locally:

remote_file “#{ENV[‘SYSTEMDRIVE’]}\\Win8.1AndW2K12R2-KB3066437-x64.msu” do

 source “”


There are two key takeaways here:

  • When you reference Windows paths in Chef recipes, you need to use \\ in place of \. Ruby sees the \ as the escape character, so you need one to escape the other.
  • Chef recipes can leverage environment variables with ENV[‘MyVariableName’].

As a natural segue, Chef provided me with significant benefits when working with environments. Ingredients like accounts, urls, ip schemes, and even the number of nodes in a particular app vary by environment. Chef allows you to use the environment to override values in a recipe. I won’t go any deeper into the discussion about environments here, but it is a topic you should become very familiar with if you’ll be using Chef.

Operations Manager

Operations Manager is pretty straightforward. After the prerequisites are installed, all you need to do is call the resource, for example:

dsc_resource ‘WebConsole’ do

 resource :xSCOMWebConsoleServerSetup

 property :Ensure, ‘Present’

 property :SourceFolder, ‘SCOM’

 property :SourcePath, “#{ENV[‘SYSTEMDRIVE’]}\\Sources”

 property :SetupCredential, ps_credential(“#{node[‘serverBase’][‘netbiosName’]}\\#{admin[‘id’]}”,admin[‘password’])

 property :ManagementServer, node[‘scom’][‘mgmtServer’]

 notifies :reboot_now, ‘reboot[now]’, :immediately


One thing worth mentioning is that when you use pscredential in a recipe, Chef provides a function to build the credential object:


Service Management Automation

Service Management Automation (SMA) is three resources for a full standalone instance:

  • SCSMAWebServiceServerSetup
  • xSCSMARunbookWorkerServerSetup
  • xSCSMAPowerShellSetup

Again, when the prerequisites are in place, it’s a pretty quick installation to set up a standalone server. Additionally, it’s really nice to use Chef to install the correct modules on all my runbook servers.

dsc_resource ‘SMAPS’ do

 resource :xSCSMAPowerShellSetup

 property :Ensure, ‘Present’

 property :SourcePath, “#{ENV[‘SYSTEMDRIVE’]}/Sources”

 property :SetupCredential, ps_credential(“#{node[‘serverBase’][‘netbiosName’]}\\#{smaSetupAccount[‘id’]}”,smaSetupAccount[‘password’])

 property :SourceFolder, ‘SMAInstall’


Service Manager

Service Manager is a slightly different beast. As of this writing, there are no DSC resources for deploying it. Luckily, Chef has a pretty robust PowerShell_script resource, which is a lot easier to use than the DSC script resource (in my experience). You need to only write a script, put it in a string, and insert variable substitutions to change whatever you need to change.

When you are going to use it, be sure you set up a guard condition—a “not_if” or “only_if” script, which will allow your resource to be idempotent.

I had a big issue with Service Manager’s installation script. Start-Process, which I used to run the installation, wouldn’t let me swap the user running the setup. It made it difficult to run unattended at first. As with everything else in this process, Chef had a pretty easy answer for this issue. I set up the Chef client to run as a task under the appropriate account and let it run.

Here’s an example of using the PowerShell_script resource to provision disks:

powershell_script ‘multiple disks’ do

 code <<-MYCODE

             $disks = get-disk | where {$_.OperationalStatus -match “Offline”}

             foreach ($d in $disks)


                         $d | Initialize-Disk -Passthru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -confirm:$false



 only_if ‘(get-disk | where {$_.OperationalStatus -match “Offline”}).count -ge 1’


ruby, the language Chef uses, lets you setup multi line strings like powershell’s here string. The syntax is like:


some text


You can wrap longer PowerShell scripts in a multiline string construct and add it as an argument for the code parameter on the PowerShell_script resource. The only_if parameter ensures that the script won’t run unless it’s necessary. Only_if and Not_if in the PowerShell script resource respond to a Boolean value returned by the script.

Why add Chef?

I wanted to highlight why I added Chef on top of DSC. Chef has some really cool functionality, which allowed me to speed up my development cycles and releases. Here are some of the key features:

Handling password distribution

One of the major issues I had with DSC on its own was securely distributing passwords. Chef made that pretty simple. You can encrypt data bag items, and by using a cool feature called chef-vault, you can use the same certificates that Chef distributes automatically to decrypt those items from appropriate clients.

Distributing resources

Because Chef executes each resource independently of the others, it lets me use DSC to copy and extract DSC resources. This was always one of my major issues with DSC.

Running PowerShell scripts

If you’ve tried to use the DSC script resource a lot, you’ve likely run into issues expanding variables. The DSC script resource won’t let you reference variables from the broader configuration without a lot of messing around. It’s complicated and hard to use. With Chef, it’s simple. I write the script and use Chef’s variable system to insert values as needed.

Running as a task

DSC runs as a task that runs as the system. With Chef, you have options: you can run as a service or as a task. That task can then be configured to run with all the arguments of any other task. I can swap the user or the execution time, and the task is simple and straightforward. Don’t get me wrong, the LCM is awesome, but I definitely don’t miss using it.


This is one of the things that most attracted me to Chef. Having the ability to set certain parameters that change depending on your environment (test/dev/uat/prod) is incredibly valuable. I write one deployment configuration (“recipe” in Chef speak), and it changes its characteristics based solely on the environment it’s in. Ultimately, I swapped from using only DSC to using DSC and Chef together when I found myself writing my own environment system.

Order of operations

Resources are always executed in order and, unless otherwise specified, a failure in a resource stops execution of the client immediately. Always knowing where you had an issue greatly simplifies any needed troubleshooting. Another benefit is that the Chef client writes the details of its last run in a log, enabling you to review the details of past runs at your convenience.


Thank you, Jason, for a way cool blog post.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. Also check out my Microsoft Operations Management Suite Blog. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy


Discussion is closed.

Feedback usabilla icon