Writing Manifests for Windows
This documentation applies to Puppet ≥ 2.7.6 and Puppet Enterprise ≥ 2.5. Earlier versions may behave differently.
Just as on *nix systems, Puppet manages resources on Windows using manifests written in the Puppet language. There are several major differences to be aware of when writing manifests that manage Windows resources:
- Windows primarily uses the backslash as its directory separator character, and Ruby handles it differently in different circumstances. You should learn when to use and when to avoid backslashes.
- Most classes written for *nix systems will not work on Windows nodes; if you are managing a mixed environment, you should use conditionals and Windows-specific facts to govern the behavior of your classes.
- Puppet generally does the right thing with Windows line endings.
- Puppet supports a slightly different set of resource types on Windows.
File Paths on Windows
Windows file paths must be written in different ways at different times, due to various tools’ conflicting rules for backslash use.
- Windows file system APIs accept both the backslash (
\) and forwardslash (/) to separate directory and file components in a path. - Some Windows programs only accept backslashes in file paths.
- *nix shells and many programming languages — including the Puppet language — use the backslash as an escape character.
As a result, any system that interacts with *nix and Windows systems as equal peers will unavoidably have complicated behavior around backslashes.
The following guidelines will help you use backslashes safely in Windows file paths with Puppet.
Forward Slashes vs. Backslashes
In many cases, you can use forward slashes instead of backslashes when specifying file paths.
Forward slashes MUST be used:
-
In template paths passed to the
templatefunction. For example:file {'C:/warning.txt': ensure => present, content => template('my_module/warning.erb'), } -
In Puppet URLs in a
fileresource’ssourceattribute. -
When part of the
modulepathconfiguration option, e.g.puppet apply --modulepath="Z:/path/to/my/modules" "Z:/path/to/my/site.pp"(This restriction applies only to versions of Puppet prior to 3.0.)
Forward slashes SHOULD be used in:
- The title or
pathattribute of afileresource - The
sourceattribute of apackageresource - Local paths in a
fileresource’ssourceattribute - The
commandof anexecresource, unless the executable requires backslashes, e.g. cmd.exe
Forward slashes MUST NOT be used in:
- The
commandof ascheduled_taskresource. - The
install_optionsof apackageresource.
The Rule
If Puppet itself is interpreting the file path, forward slashes are okay. If the file path is being passed directly to a Windows program, forward slashes may not be okay.
Using Backslashes in Double-Quoted Strings
Puppet supports two kinds of string quoting. Strings surrounded by double quotes (") allow variable interpretation and many escape sequences (including the common \n for a newline), so care must be taken to prevent backslashes from being mistaken for escape sequences.
When using backslashes in a double-quoted string, you must always use two backslashes for each literal backslash. There are no exceptions and no special cases.
Using Backslashes in Single-Quoted Strings
Strings surrounded by single quotes (') do not allow variable interpretation, and the only escape sequences permitted are \' (a literal single quote) and \\ (a literal backslash).
Lone backslashes can usually be used in single-quoted strings. However:
- When a backslash occurs at the very end of a single-quoted string, a double backslash must be used instead of a single backslash. For example:
path => 'C:\Program Files(x86)\\' - When a literal double backslash is intended, a quadruple backslash must be used.
The Rule
In single-quoted strings:
- A double backslash always means a literal backslash.
- A single backslash usually means a literal backslash, unless it is followed by a single quote or another backslash.
Notable Windows Facts
Windows nodes with a default install of Puppet will return the following notable facts, which can be useful when writing manifests:
Identifying Facts
The following facts can help you determine whether a given machine is running Windows:
kernel => windowsoperatingsystem => windowsosfamily => windows
Windows-Specific Facts
The following facts are either Windows-only, or have different values on Windows than on *nix:
env_windows_installdir— This fact will contain the directory in which Puppet was installed.id— This fact will be<DOMAIN>\<USER NAME>. You can use the user name to determine whether Puppet is running as a service or was triggered manually.
Line Endings in Windows Text Files
Windows uses CRLF line endings instead of *nix’s LF line endings.
- If the contents of a file are specified with the
contentattribute, Puppet will write the content in “binary” mode. To create files with CRLF line endings, the\r\nescape sequence should be specified as part of the content. - If a file is being downloaded to a Windows node with the
sourceattribute, Puppet will transfer the file in “binary” mode, leaving the original newlines untouched. -
Non-
fileresource types that make partial edits to a system file (most notably thehosttype, which manages the%windir%\system32\drivers\etc\hostsfile) manage their files in text mode, and will automatically translate between Windows and *nix line endings.Note: When writing your own resource types, you can get this behavior by using the
flatfiletype.
Resource Types
Puppet can manage the following resource types on Windows nodes:
file
file { 'c:/mysql/my.ini':
ensure => 'file',
mode => '0660',
owner => 'mysql',
group => 'Administrators',
source => 'N:/software/mysql/my.ini',
}
Puppet can manage files and directories, including owner, group, permissions, and content. Symbolic links are not supported.
- If an
ownerorgroupare specified for a file, you must also specify amode. Failing to do so can render a file inaccessible to Puppet. See here for more details. - Windows NTFS filesystems are case-preserving, but case-insensitive; Puppet is case-sensitive. Thus, you should be consistent in the case you use when referring to a file resource in multiple places in a manifest.
- In order to manage files that it does not own, Puppet must be running as a member of the local Administrators group (on Windows 2003) or with elevated privileges (Windows 7 and 2008). This gives Puppet the
SE_RESTORE_NAMEandSE_BACKUP_NAMEprivileges it requires to manage file permissions. - Permissions modes are set as though they were *nix-like octal modes; Puppet translates these to the equivalent access controls on Windows.
- The read, write, and execute permissions translate to the
FILE_GENERIC_READ,FILE_GENERIC_WRITE, andFILE_GENERIC_EXECUTEaccess rights. - The owner of a file/directory always has the
FULL_CONTROLaccess right. - The
EveryoneSID is used to represent users other than the owner and group.
- The read, write, and execute permissions translate to the
- Puppet cannot set permission modes where the group has higher permissions than the owner, or other users have higher permissions than the owner or group. (That is, 0640 and 0755 are supported, but 0460 is not.) Directories on Windows can have the sticky bit, which makes it so users can only delete files if they own the containing directory.
- On Windows, the owner of a file can be a group (e.g.
owner => 'Administrators') and the group of a file can be a user (e.g.group => 'Administrator'). The owner and group can even be the same, but as that can cause problems when the mode gives different permissions to the owner and group (like0750), this is not recommended. - The source of a file can be a puppet URL, a local path, or a path to a file on a mapped drive.
- When downloading a file from a puppet master with a
puppet:///URI, Puppet will set the permissions mode to match that of the remote file. Be sure to set the proper mode on any remote files.
user
Puppet can create, edit, and delete local users. Puppet does not support managing domain user accounts, but can add (and remove) domain user accounts to local groups.
- The
comment,home, andpasswordattributes can be managed, as well as groups to which the user belongs. - Passwords can only be specified in cleartext. Windows does not provide an API for setting the password hash.
- The user SID is available as a read-only parameter. Attempting to set the parameter will fail
- User names are case-sensitive in Puppet manifests, but insensitive on Windows. Make sure to consistently use the same case in manifests.
Security Identifiers (SID)
On Windows, user and group account names can take multiple forms, e.g. Administrators, <host>\Administrators, BUILTIN\Administrators, S-1-5-32-544. When comparing two account names, puppet always first transforms account names into their canonical SID form and compares the SIDs instead.
group
Puppet can create, edit, and delete local groups, and can manage a group’s members. Puppet does not support managing domain group accounts, but a local group can include both local and domain users as members.
- The group SID is available as a read-only parameter. Attempting to set the parameter will fail.
- Group names are case-sensitive in puppet manifests, but insensitive on Windows. Make sure to consistently use the same case in manifests.
- Nested groups are not supported. (Group members must be users, not other groups.)
scheduled_task
scheduled_task { 'Daily task':
ensure => present,
enabled => true,
command => 'C:\path\to\command.exe',
arguments => '/flags /to /pass',
trigger => {
schedule => daily,
every => 2, # Defaults to 1
start_date => '2011-08-31', # Defaults to 'today'
start_time => '08:00', # Must be specified
}
}
Puppet can create, edit, and delete scheduled tasks. It can manage the task name, the enabled/disabled status, the command, any arguments, the working directory, the user and password, and triggers. For more information, see the reference documentation for the scheduled_task type. This is a Windows-only resource type.
- Puppet does not support “every X minutes” type triggers.
package
package { 'mysql':
ensure => installed,
provider => 'msi', # deprecated in Puppet 3.0
source => 'N:/packages/mysql-5.5.16-winx64.msi',
install_options => { 'INSTALLDIR' => 'C:\mysql-5.5' },
}
Puppet can install and remove MSI packages, including specifying package-specific install options, e.g. install directory.
Identifying Packages
The title or name of the package must match the value of the DisplayName property in the registry, which is also the value displayed in Add/Remove Programs. Alternately, when a package name is not unique across versions (e.g. VMWare Tools, or where there are 32- and 64-bit versions with the same name), we provide the ability to specify the package’s PackageCode as the package name. This is a GUID that’s unique across all MSI builds. For instance:
package { '{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}':
ensure => installed,
source => 'the.msi',
provider => windows
}
To find the PackageCode from an MSI, you can use Orca, or you can get to it programmatically with Ruby:
require 'win32ole'
installer = WIN32OLE.new('WindowsInstaller.Installer')
db = installer.OpenDatabase(path, 0) # where 'path' is the path to the MSI
puts db.SummaryInformation.Property(9)
Additional Notes on Windows Packages
- The source parameter is required, and must refer to a local .msi file, a file from a mapped drive, or a UNC path. You can distribute packages as
fileresources. Puppet URLs are not currently supported for thepackagetype’ssourceattribute. - The
install_optionsattribute is package-specific; refer to the documentation for the package you are trying to install.- Any file path arguments within the
install_optionsattribute (such asINSTALLDIR) should use backslashes, not forward slashes.
- Any file path arguments within the
- As of Puppet 3.0,
windowsis the default provider parameter for all Windows packages. Usingmsiwill result in a deprecation warning.
service
service { 'mysql':
ensure => 'running',
enable => true,
}
Puppet can start, stop, enable, disable, list, query and configure services. It does not support configuring service dependencies, account to run as, or desktop interaction.
- Use the short service name (e.g.
wuauserv) in Puppet, not the display name (e.g.Automatic Updates). - Setting the
enableattribute totruewill assign a service the “Automatic” startup type; settingenabletomanualwill assign the “Manual” startup type.
exec
Puppet can execute binaries (exe, com, bat, etc.), and can log the child process output and exit status.
- If an extension for the
commandis not specified (for example,rubyinstead ofruby.exe), Puppet will use thePATHEXTenvironment variable to resolve the appropriate binary.PATHEXTis a Windows-specific variable that lists the valid file extensions for executables. - Puppet does not support a shell provider for Windows, so if you want to execute shell built-ins (e.g.
echo), you must provide a completecmd.exeinvocation as the command. (For example,command => 'cmd.exe /c echo "foo"'.) - When executing Powershell scripts, you must specify the
remotesignedexecution policy as part of thepowershell.exeinvocation:
exec { 'test':
command => 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -executionpolicy remotesigned -file C:\test.ps1',
}
host
Puppet can manage entries in the hosts file in the same way that is supported on Unix platforms.