Managing IIS With Puppet via Powershell DSC

Use Case:

Many of us in DevOps/Cloud/Site Reliability/System Engineering have long been using Puppet to manage our Apache and Nginx configurations. However it seems like every Windows deployment I come across using IIS is either not in any form of config management, or is managed through a series of VBScript and PowerShell scripts or System Center. If your organization is big enough to afford System Center this isn’t really much of an issue for you; however for those of us managing IIS web farms without SCCM, Microsoft has extended a nice olive branch with the delivery of PowerShell Desired State Configuration.

Given that most of us work with such broad toolsets, the idea of adding yet another configuration management platform into the mix seems less than ideal. However, there is an official Puppet Forge module that allows you to leverage PowerShell DSC within your Puppet code. What I found in my journey of doing this is that, while there is some decent documentation, there are pieces that clearly seem not to be well documented that required figuring it out the hard way. In this blog post I’ll cover and distill what I’ve learned in configuration of IIS through PowerShell DSC via Puppet.

Prerequisites:

This blog post will assume that you have already installed the PowerShell DSC forge module. I will link the module and its dependencies below; if you are unsure how to install Forge modules, see the documentation on the link to the module below.

This blog post will also assume that you have already installed IIS either in your AMI/Template or via Puppet. Great, now that that’s all out of the way, let’s get started.

 

Overview Example Class:

Before diving into the weeds in each section, I wanted to provide a code sample of a single application pool, website, virtual directory, and web application, complete with the DSC dependencies:

 

class webhosting::clientname::sites::dev {
 
dsc_windowsfeature{'iis':
  dsc_ensure => 'Present',
  dsc_name => 'Web-Server',
}
dsc_windowsfeature{'aspnet45':
  dsc_ensure => 'Present',
  dsc_name => 'Web-Asp-Net45',
}
dsc_windowsfeature{'iisscriptingtools':
  dsc_ensure => 'Present',
  dsc_name => 'Web-Scripting-Tools',
}
 
#App Pool Creation
dsc_xwebapppool{'dev.example.com':
  dsc_name => 'dev.example.com',
  dsc_ensure => 'Present',
  dsc_enable32bitapponwin64 => true,
  dsc_managedruntimeversion => 'v4.0',
  dsc_managedpipelinemode => 'Integrated',
  dsc_identitytype => 'ApplicationPoolIdentity',
  dsc_state => 'Started',
  require => Dsc_windowsfeature['iis'],
}
 
#Website Creation
dsc_xwebsite{'dev.example.com':
  dsc_ensure => 'Present',
  dsc_name => 'dev.example.com',
  dsc_state => 'Started',
  dsc_physicalpath => 'D:\\www\\dev.example.com\\webroot',
  dsc_applicationpool => 'dev.example.com',
  dsc_bindinginfo => [{
  ipaddress => '*',
    protocol => 'HTTP',
    port => 80,
    hostname => 'dev.example.com',
    },
    {
    ipaddress => '*',
    protocol => 'HTTPS',
    port => 443,
    hostname => 'dev.example.com',
    certificatethumbprint => '<certificatethumbprintgoeshere>',
    certificatestorename => 'WebHosting',
    }],
 require => Dsc_xwebapppool['dev.example.com'],
  }
 
#Web Applications
dsc_xwebapplication{'AwesomeApp':
  dsc_ensure => 'Present',
  dsc_name => '/AwesomeApp',
  dsc_website => 'dev.example.com',
  dsc_webapppool => 'dev.example.com',
  dsc_physicalpath => 'D:\\www\\dev.example.com\\webroot',
  require => Dsc_xwebsite['dev.example.com'],
  }
 
#Virtual directories
dsc_xwebvirtualdirectory{'AwesomeApp':
  dsc_ensure => 'Present',
  dsc_name => 'AwesomeApp',
  dsc_website => 'dev.example.com',
  dsc_webapplication => 'AwesomeApp',
  dsc_physicalpath => 'D:\\webapplicatons\\AwesomeApp',
  require => Dsc_xwebapplication['AwesomeApp'],
  }
}

DSC Windows Feature

Starting at the top and taking this a chunk at a time, we see after the opening Puppet class statement that there are several dsc_windows_feature statements. These statements install the PowerShell DSC packages on the endpoint nodes. PowerShell DSC wrapped in Puppet assumes that you are using the pull model style of using DSC. What essentially happens on the Puppet run is that your Puppet DSC code gets converted into PowerShell DSC code and run locally on the machine. DSC module can be found at https://gallery.technet.microsoft.com/scriptcenter. Note that modules beginning with an X are considered experimental. That said, most of the experimental modules in my experience have been stable.

 

Configuring The Rest

Beyond this point, the rest of the Puppet code you will see will be prefixed with dsc_. Essentially, to write DSC code in Puppet you will use the same values outlined in the DSC documentation, just prefixed with the dsc_ and using the Ruby hash rockets => instead of =. See the example below:

DSC Example:

    xWebsite DefaultSite
        {
            Ensure          = "Present"
            Name            = "Default Web Site"
            State           = "Stopped"
            PhysicalPath    = "C:\inetpub\wwwroot"
        }

Puppet Example:

     dsc_xWebsite{'DefaultSite':
            dsc_ensure       => 'Present',
            dsc_name         => 'Default Web Site',
            dsc_state        => 'Stopped',
            dsc_physicalpath => 'C:\\inetpub\\wwwroot',
        }

At this point, you can configure your applications specific to your environments. Much like any other Puppet code there are obvious dependencies (can’t create a website that depends on an application pool unless the pool already exists). For this you can use the normal Puppet meta parameters such as before and require statements to resolve dependencies. For IIS-specific DSC parameters see the readme for Microsoft’s XWebAdministration module here:  https://github.com/PowerShell/xWebAdministration

 

Don’t forget to prefix the parameters in the readme with dsc_ when converting to Puppet code. Happy configuring and Puppeting! Until next time, may your servers always be up and your coffee mugs never empty!

Can’t Change Network Location Windows Server 2012 & 2012 R2

Out of the box the last few versions of Windows Server have had a substantial focus on security which is in general a great thing. However if you’ve experienced the “fun” wonders of not being able to RDP or ping your newly setup Windows server or have encountered issues with it after changing networks you may want to check your network location to see if it shows as Private or Public. Not only do these have a vastly different set of default firewall rules in general any network you connect your server to should be a private network.

Great, so how do we change the network location? Well for starters you can’t simply click the location and change it to public like you can on a Windows desktop machine. To change this we’ll need to enter the run dialog box (right click start and choose run). Then type secpol.msc and hit enter.

Screen Shot 2016-07-30 at 7.31.13 PM

Once you’ve done this you will want to choose “Network List Manager Policies” on the left hand side of the msc window.

Screen Shot 2016-07-30 at 7.31.30 PM

Next we’ll right click “unidentified networks” and choose properties. The following window will appear, select the radio button for “private” and click ok. You should now see your network change from public to private.

Screen Shot 2016-07-30 at 7.31.47 PM

Scripted Application Installs For Windows With Chocolatey

What is Chocolatey and Why Would I Use It

Chocolatey is an application repository with a commandline provider similar to apt or yum on Linux. The great thing about Chocolatey is it makes software installation scriptable. Think of setting up new workstations or servers. Depending on the environment there is a ton of software to install, things like notepad++, .Net Framework, New Relic, or if you’re setting up a dev environment maybe Visual Studio, notepad++, Adobe Reader, Java JDK, etc. Now you can automate this with a PowerShell script, or better yet if you use Puppet you can leverage the Puppet forge module for Chocolatey.

 

Installation

To install Chocolatey run the following in PowerShell:

Set-ExecutionPolicy RemoteSigned
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))

That’s it now Chocolatey is installed.

 

Installing Applications

To install applications in Chocolately you will find the commands listed next to the software in the Chocolatey packages library at https://chocolatey.org/packages or you can use the commandline search tool (See https://github.com/chocolatey/choco/wiki/CommandsList for examples). You can also setup your own local Chocolatey server if you are in an enterprise environment, however this is outside the scope of this article. Below is an example of several common applications being installed via Chocolatey in PowerShell

choco install googlechrome
choco install firefox
choco install git
choco install adobereader
choco install notepadplusplus
choco install 7zip
choco install ccleaner
choco install sysinternals
choco install filezilla
choco install ruby
choco install nscp
choco install puppet
choco install zabbix-agent

 

Puppet Forge Module

If your organization is already using Puppet to do config management you can use Chocolatey as a provider in Puppet. To install the module on your Puppet master run the following command:

puppet module install chocolatey-chocolatey

To use the module you can create a Puppet class for you nodes refer to the usage instructions located at https://forge.puppet.com/chocolatey/chocolatey#usage