Managing Windows nodes
You can use PE to manage your Windows configurations, including controlling services, creating local group and user accounts, and performing basic management tasks using Forge modules.
Basic tasks and concepts in Windows
This section is meant to help familiarize you with several common tasks used in Puppet Enterprise (PE) with Windows agents, and explain the concepts and reasons behind performing them.
Practice tasks
In other locations in the documentation, these can be found as steps in tasks, but they are not explained as thoroughly.
Write a simple manifest
Puppet manifest files are lists of resources that have a unique title and a set of named attributes that describe the desired state.
You need a text editor, for example Visual Studio Code (VS Code), to create manifest files. Puppet has an extension for VS Code that supports syntax highlighting of the Puppet language. Editors like Notepad++ or Notepad won't highlight Puppet syntax, but can also be used to create manifests.
Manifest files are written in Puppet code, a domain specific language (DSL) that defines the desired state of resources on a system, such as files, users, and packages. Puppet compiles these text-based manifests into catalogs, and uses those to apply configuration changes.
Note the following details in this file resource example:
-
Puppet uses a basic syntax of
type { title: }
, wheretype
is the resource type — in this case it’sfile
. -
The resource title (the value before the
:
) isC:\\Temp\\foo.txt
. The file resource uses the title to determine where to create the file on disk. A resource title must always be unique within a given manifest. -
The
ensure
parameter is set topresent
to create the file on disk, if it's not already present. Forfile
type resources, you can also use the valueabsent
, which removes the file from disk if it exists. -
The
content
parameter is set toThis is some text in my file
, which writes that value to the file.
Validate your manifest with puppet parser validate
You can validate that a manifest's syntax is correct by
using the command puppet parser
validate
Launch the Puppet command prompt
A lot of common interactions with Puppet are done via the command line.
The Puppet command prompt has a few details worth noting:
- Several important batch files live in the current working
directory,
C:\Program Files\Puppet Labs\Puppet\bin
. The most important of these batch files ispuppet.bat
. Puppet is a Ruby based application, andpuppet.bat
is a wrapper around executing Puppet code throughruby.exe
. -
Running the command prompt with Puppet rather than just the default Windows command prompt ensures that all of the Puppet tooling is in PATH, even if you change to a different directory.
Simulate a Puppet run with --noop
Puppet has a switch that you can use to test if manifests make the intended changes. This is referred to as non-enforcement or no-op mode.
puppet apply c:\myfiles\file.pp --noop
in the command
prompt:
C:\Program Files\Puppet Labs\Puppet\bin>puppet apply c:\myfiles\file.pp --noop
Notice: Compiled catalog for win-User.localdomain in environment production in 0.45 seconds
Notice: /Stage[main]/MainFile[C:\Temp\foo.txt]/ensure: current value absent, should be present (noop)
Notice: Class[Main]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Notice: Applied catalog in 0.03 seconds
Puppet shows you the changes it would make, but does not actually make the changes. It would create a new file at C:\Temp\foo.txt
, but it hasn't, because you used --noop
.
Enforce the desired state with puppet apply
When the output of the simulation shows the changes you
intend to make, you can start enforcing these changes with the puppet apply
command.
puppet
apply c:\myfiles\file.pp
.
To see more details about what this command did, you can
specify additional options, such as --trace
, --debug
, or --verbose
, which can help you diagnose problematic code. If
puppet apply
fails, Puppet outputs a full stack trace.
Puppet enforces the resource state you've described
in file.pp
, in this case
guaranteeing that a file (c:\Temp\foo.txt
) is present and has the contents This is some text in my file
.
Understanding idempotency
A key feature of Puppet is its idempotency: the ability to repeatedly apply a manifest to guarantee a desired resource state on a system, with the same results every time.
If a given resource is already in the desired state, Puppet performs no actions. If a given resource is not in the desired state, Puppet takes whatever action is necessary to put the resource into the desired state. Idempotency enables Puppet to simulate resource changes without performing them, and lets you set up configuration management one time, fixing configuration drift without recreating resources from scratch each time Puppet runs.
To demonstrate how Puppet can be applied
repeatedly to get the same results, change the manifest at c:\myfiles\file.pp
to the following:
file { 'C:\\Temp\\foo.txt':
ensure => present,
content => 'I have changed my file content.'
}
Apply the manifest by running puppet apply c:\myfiles\file.pp
. Open c:\Temp\foo.txt
and notice that Puppet changes the
file's contents.
Applying the manifest again with puppet apply c:\myfiles\file.pp
results in no changes to the system, demonstrating
that Puppet behaves idempotently.
Many of the samples in Puppet documentation
assume that you have this basic understanding of creating and editing manifest files, and
applying them with puppet apply
.
Additional command line tools
Once you understand how to write manifests, validate them,
and use puppet apply
to enforce your
changes, you're ready to use commands such as puppet
agent
, puppet resource
, and
puppet module
install
.
puppet agent
Like puppet apply
, the puppet agent
command line
tool applies configuration changes to a system. However, puppet
agent
retrieves compiled catalogs from a Puppet Server, and applies them to the local system. Puppet is installed as a Windows service, and by default tries to contact the
primary server every 30 minutes by running puppet agent
to retrieve
new catalogs and apply them locally.
puppet resource
puppet resource
to query the state of a particular type
of resource on the system. For example, to list all of the users on a system, run
the command puppet resource user
. The computer used for this example has three local user accounts: Administrator, Guest, and vagrant. Note that the output is the same format as a manifest, and you can copy and paste it directly into a manifest.
puppet module install
Puppet includes many core resource types, plus you can extend Puppet by installing modules. Modules contain additional resource definitions and the code necessary to modify a system to create, read, modify, or delete those resources. The Puppet Forge contains modules developed by Puppet and community members available for anyone to use.
Puppet synchronizes modules from a primary server to
agent nodes during puppet agent
runs. Alternatively, you can use
the standalone Puppet module tool, included when you
install Puppet, to manage, view, and test
modules.
Run puppet module list
to show the list of modules installed on the
system.
To install modules, the Puppet module tool uses the
syntax puppet module install NAMESPACE/MODULENAME
. The
NAMESPACE
is registered to a module, and
MODULE
refers to the specific module name. A very common module
to install on Windows is registry
,
under the puppetlabs
namespace. So, to install the
registry
module, run puppet module install
puppetlabs/registry
.
Manage Windows services
You can use Puppet to manage Windows services, specifically, to start, stop, enable, disable, list, query, and configure services. This way, you can ensure that certain services are always running or are disabled as necessary.
You write Puppet code to manage services in the manifest. When you apply the manifest, the changes you make to the service are applied.
puppet resource
command, which emits code as well as
applying changes.Ensure a Windows service is running
There are often services that you always want running in your infrastructure.
service { '<service name>':
ensure => 'running'
}
Example
service { 'w32time':
ensure => 'running'
}
Stop a Windows service
Some services can impair performance, or might need to be stopped for regular maintenance.
service { '<service name>':
ensure => 'stopped',
enable => 'false'
}
Example
service { 'defragsvc':
ensure => 'stopped',
enable => 'false'
}
Schedule a recurring operation with Windows Task Scheduler
Regularly scheduled operations, or tasks, are often necessary on Windows to perform routine system maintenance.
If you need to sync files from another system on the network, perform backups to another disk, or execute log or index maintenance on SQL Server, you can use Puppet to schedule and perform regular tasks. The following shows how to regularly delete files.
C:\Windows\Temp
at 8 AM each day, create a
resource called scheduled_task
with
these attributes:
scheduled_task { 'Purge global temp files':
ensure => present,
enabled => true,
command => 'c:\\windows\\system32\\cmd.exe',
arguments => '/c "del c:\\windows\\temp\\*.* /F /S /Q"',
trigger => {
schedule => daily,
start_time => '08:00',
}
}
Example
In addition to creating a trivial daily task at a specified time, the scheduled task resource supports a number of other more advanced scheduling capabilities, including more fine-tuned scheduling. For example, to change the above task to instead perform a disk clean-up every 2 hours, modify the trigger definition:
scheduled_task { 'Purge global temp files every 2 hours':
ensure => present,
enabled => true,
command => 'c:\\windows\\system32\\cmd.exe',
arguments => '/c "del c:\\windows\\temp\\*.* /F /S /Q"',
trigger => [{
day_of_week => ['mon', 'tues', 'wed', 'thurs', 'fri'],
every => '1',
minutes_interval => '120',
minutes_duration => '1440',
schedule => 'weekly',
start_time => '07:30'
}],
user => 'system',
}
Manage Windows users and groups
Puppet can be used to create local group and user accounts. Local user accounts are often desirable for isolating applications requiring unique permissions.
Manage administrator accounts
It is often necessary to standardize the local Windows Administrator password across an entire Windows deployment.
'Administrator'
as the resource title like
so:
user { 'Administrator':
ensure => present,
password => 'yabbadabba'
}
Configure an app to use a different account
You might not always want to use the default user for an application, you can use Puppet to create users for other applications, like ASP.NET.
Network Service
, create
a user and exec resource:
user { 'aspnet_banking_app':
ensure => present,
managehome => true,
comment => 'ASP.NET Service account for Banking application',
password => 'banking_app_password',
groups => ['IIS_IUSRS', 'Users'],
auth_membership => 'minimum',
notify => Exec['regiis_aspnet_banking_app']
}
exec { 'regiis_aspnet_banking_app':
path => 'c:\\windows\\Microsoft.NET\\Framework\\v4.0.30319',
command => 'aspnet_regiis.exe -ga aspnet_banking_app',
refreshonly => true
}
In this example, the user is created in the appropriate groups, and the ASP.NET IIS registration command is run after the user is created to ensure file permissions are correct.
In the user resource, there are a few important details to note:
managehome
is set to create the user's home directory on disk.auth_membership
is set to minimum, meaning that Puppet makes sure theaspnet_banking_app
user is a part of theIIS_IUSRS
andUsers
group, but doesn't remove the user from any other groups it might be a part of.notify
is set on the user, andrefreshonly
is set on theexec
. This tells Puppet to runaspnet_regiis.exe
only when theaspnet_banking_app
is created or changed.
Manage local groups
Local user accounts are often desirable for isolating applications requiring unique permissions. It can also be useful to manipulate existing local groups.
group { 'Administrators':
ensure => 'present',
members => ['DOMAIN\\User'],
auth_membership => false
}
In this case, auth_membership
is set to false to ensure that DOMAIN\User
is present in the Administrators group, but that
other accounts that might be present in Administrators are not removed.
Note that the groups
attribute of user
and the members
attribute of group
might both accept SID values, like the
well-known SID for Administrators, S-1-5-32-544.
Executing PowerShell code
Some Windows maintenance tasks require the use of Windows Management Instrumentation (WMI), and PowerShell is the most useful way to access WMI methods. Puppet has a special module that can be used to execute arbitrary PowerShell code.
A common Windows maintenance tasks is to disable Windows drive indexing, because it can negatively impact disk performance on servers.
$drive = 'C:'
exec { 'disable-c-indexing':
provider => powershell,
command => "\$wmi_volume = Get-WmiObject -Class Win32_Volume -Filter 'DriveLetter=\"${drive}\"'; if (\$wmi_volume.IndexingEnabled -ne \$True) { return }; \$wmi_volume | Set-WmiInstance -Arguments @{IndexingEnabled = \$False}",
unless => "if ((Get-WmiObject -Class Win32_Volume -Filter 'DriveLetter=\"${drive}\"').IndexingEnabled) { exit 1 }",
}
Using the Windows built-in
WBEMTest tool, running this manifest sets IndexingEnabled
to FALSE
,
which is the desired behavior.
exec
sets a few important attributes: -
The provider is configured to use PowerShell (which relies on the module).
-
The command contains inline PowerShell, and as such, must be escaped with PowerShell variables preceded with
$
must be escaped as\$
. -
The
unless
attribute is set to ensure that Puppet behaves idempotently, a key aspect of using Puppet to manage resources. If the resource is already in the desired state, Puppet does not modify the resource state.
Using templates to better manage Puppet code
While inline PowerShell is usable as an exec
resource in your manifest, such code can be difficult to read and maintain, especially when it
comes to handling escaping rules.
For executing multi-line scripts, use Puppet templates instead. The following example shows how you can use a template to organize the code for disabling Windows drive indexing.
$drive = 'C:'
exec { 'disable-c-indexing':
command => template('Disable-Indexing.ps1.erb'),
provider => powershell,
unless => "if ((Get-WmiObject -Class Win32_Volume -Filter 'DriveLetter=\"${drive}\"').IndexingEnabled) { exit 1 }",
}
The PowerShell code for Disable-Indexing.ps1.erb becomes:
function Disable-Indexing($Drive)
{
$drive = Get-WmiObject -Class Win32_Volume -Filter "DriveLetter='$Letter'"
if ($drive.IndexingEnabled -ne $True) { return }
$drive | Set-WmiInstance -Arguments @{IndexingEnabled=$False} | Out-Null
}
Disable-Indexing -Drive '<%= @driveLetter %>'
Using Windows modules
You can use modules from the Forge to perform basic management tasks on Windows nodes, such as managing access control lists and registry keys, and installing and creating your own packages.
Manage permissions with the acl
module
The puppetlabs-acl
module helps you manage access control lists (ACLs), which
provide a way to interact with permissions for the Windows
file system. This module enables you to set basic permissions up to very advanced
permissions using SIDs (Security Identifiers) with an access mask, inheritance, and
propagation strategies. First, start with querying some existing permissions.
View file permissions with ACL
ACL is a custom type and provider, so you can use puppet resource
to look at existing file and
folder permissions.
For some types, you can use the command puppet resource <TYPE NAME>
to get all instances of that
type. However, there could be thousands of ACLs on a Windows system, so it's best to specify the folder you
want to review the types in. Here, check c:\Users
to see what permissions it contains.
puppet resource acl c:\Users
acl { 'c:\Users':
inherit_parent_permissions => 'false',
permissions => [
{identity => 'SYSTEM', rights=> ['full']},
{identity => 'Administrators', rights => ['full']},
{identity => 'Users', rights => ['read', 'execute'], affects => 'self_only'},
{identity => 'Users', rights => ['read', 'execute'], affects => 'children_only'},
{identity => 'Everyone', rights => ['read', 'execute'], affects => 'self_only'},
{identity => 'Everyone', rights => ['read', 'execute'], affects => 'children_only'}
],
}
As you can see, this particular folder does not inherit permissions from its parent folder; instead, it sets its own permissions and determines how child files and folders inherit the permissions set here.
{'identity' => 'SYSTEM', 'rights'=> ['full']}
states that the “SYSTEM” user has full rights to this folder, and by default all children and grandchildren files and folders (as these are the same defaults when creating permissions in Windows).{'identity' => 'Users', 'rights' => ['read', 'execute'], 'affects' => 'self_only'}
gives read and execute permissions to Users but only on the current directory.{'identity' => 'Everyone', 'rights' => ['read', 'execute'], 'affects' => 'children_only'}
gives read and execute permissions to everyone, but only on subfolders and files.
Create a Puppet managed permission
Now the permissions have been set up for this directory. You can get into more advanced permission scenarios if you read the usage scenarios on this module’s Forge page.
Create managed registry keys with registry
module
You might eventually need to use the registry to access
and set highly available settings, among other things. The puppetlabs-registry
module, which is also a Puppet Supported Module enables you to set both registry keys
and values.
View registry
keys
and values with puppet resource
puppetlabs-registry
is a custom type and
provider, so you can use puppet resource
to
look at existing registry settings.
It is also somewhat
limited, like the acl
module in that it is
restricted to only what is specified.
Keys are like file paths (directories) and values are like files that can have data and be of different types.
Create managed keys
Learn how to make managed registry keys, and see Puppet correct configuration drift when you try and alter them in Registry Editor.
Example
class puppetconf::disable_error_reporting {
registry_value { 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\ForceQueue':
type => dword,
data => '1',
}
registry_value { 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\DontShowUI':
type => dword,
data => '1',
}
registry_value { 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\DontSendAdditionalData':
type => dword,
data => '1',
}
registry_key { 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\Consent':
ensure => present,
}
registry_value { 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\Consent\DefaultConsent':
type => dword,
data => '2',
}
}
Create, install, and repackage packages with the chocolatey
module
Chocolatey is a package manager for Windows that is similar in design and execution to package
managers on non-Windows systems. The chocolatey
module is a Puppet Approved Module, so it's not eligible for Puppet Enterprise support services. The module has the capability to
intall and configure Chocolatey itself, and then manage software on Windows with Chocolatey packages.
View existing packages
Chocolatey has a custom provider for the package resource
type, so you can use puppet resource
to
view existing packages.
puppet resource package --param provider |
more
The additional provider parameter in this command outputs all types of installed packages that are detected by multiple providers.
Install Chocolatey
These steps are to install Chocolatey (choco.exe) itself. You use the module to ensure Chocolatey is installed.
Install a package with chocolatey
Normally, when installing packages you copy them locally first, make any required changes to bring everything they download to an internal location, repackage the package with the edits, and build your own packages to host on your internal package repository (feed). For this exercise, however, you directly install a portable Notepad++ from Chocolatey's community feed. The Notepad++ CommandLine package is portable and shouldn't greatly affect an existing system.
If you want to use this package for a production scenario, you need an internal custom
feed. This is simple to set up with the chocolatey_server
module. You could
also use Sonatype Nexus, Artifactory, or a CIFS share if you want to host packages with a
non-Windows option, or you can use anything on Windows that exposes a NuGet OData feed (Nuget is the packaging
infrastructure that Chocolatey uses). See the How To
Host Feed page of the chocolatey
wiki for more in-depth
information. You could also store packages on your primary server and use a file resource to
verify they are in a specific local directory prior to ensuring the packages.
Example
The following example ensures that Chocolatey, the Chocolatey Simple Server (an internal Chocolatey package repository), and some packages are installed. It requires the additional chocolatey/chocolatey_server module.
In c:\<FILE
PATH>\packages
you must have packages for Chocolatey, Chocolatey.Server, RoundhousE, Launchy,
and Git, as well as any of their dependencies for this to work.
case $operatingsystem {
'windows': {
Package {
provider => chocolatey,
source => 'C:\packages',
}
}
}
# include chocolatey
class {'chocolatey':
chocolatey_download_url => 'file:///C:/packages/chocolatey.0.9.9.11.nupkg',
use_7zip => false,
log_output => true,
}
# This contains the bits to install the custom server.
# include chocolatey_server
class {'chocolatey_server':
server_package_source => 'C:/packages',
}
package {'roundhouse':
ensure => '0.8.5.0',
}
package {'launchy':
ensure => installed,
install_options => ['-override', '-installArgs','"', '/VERYSILENT','/NORESTART','"'],
}
package {'git':
ensure => latest,
}
Copy an existing package and make it internal (repackaging packages)
To make the existing package local, use these steps.
Chocolatey's community feed has quite a few packages, but they are geared towards community and use the internet for downloading from official distribution sites. However, they are attractive as they have everything necessary to install a piece of software on your machine. Through the repackaging process, by which you take a community package and bring all of the bits internal or embed them into the package, you can completely internalize a package to host on an internal Chocolatey/NuGet repository. This gives you complete control over a package and removes the aforementioned production trust and control issues.
Create a package with chocolatey
Creating your own packages is, for some system administrators, surprisingly simple compared to other packaging standards.
Ensure you have at least
Chocolatey CLI (choco.exe) version 0.9.9.11
or newer for this next part.
Vagrant is installed!
Uninstall packages with Chocolatey
In addition to installing and creating packages, Chocolatey can also help you uninstall them.
To verify that the choco
autoUninstaller
feature is turned on, use
choco feature
to list the features and
their current state. If you're using include
chocolatey
or class chocolatey
to ensure Chocolatey is installed, the configuration is applied automatically (unless you
have explicitly disabled it). Starting in Chocolatey version 0.9.10
, it is enabled by default.
You can look in the Control Panel, Programs and Features to see that it’s no longer installed!