Several resource types (including file
, exec
, and package
) take file paths as values for various attributes.
When writing Puppet manifests to manage Windows systems, there are two extra issues to take into account when writing file paths: directory separators and file system redirection.
Directory Separators
Windows traditionally uses the backslash (\
) to separate directories in file paths. (For example, C:\Program Files\PuppetLabs
.) However, the Puppet language also uses the backslash (\
) as an escape character in quoted strings. This can make it awkward to write literal backslashes.
To complicate things further: the Windows file system APIs will accept both the backslash (\
) and forward-slash (/
) in file paths, but some Windows programs still only accept backslashes.
In short:
- Using forward-slashes in paths is easier, but sometimes you must use backslashes.
- When you use backslashes, you must pay extra attention to keep them from being suppressed by Puppet’s string quoting.
The following guidelines will help you use backslashes safely in Windows file paths with Puppet.
When to Use Each Kind of Slash
If Puppet itself is interpreting the file path, forward slashes are generally okay. If the file path is being passed directly to a Windows program, backslashes may be mandatory. If the file path is meant for the Puppet master, forward-slashes may be mandatory.
The most notable instances of each kind of path are listed below.
Forward-Slashes Only
Forward slashes MUST be used in:
- Template paths (e.g.
template('my_module/content.erb')
) puppet:///
URLs
Forward- and Backslashes Both Allowed
You can choose which kind of slash to use in:
- The
path
attribute or title of afile
resource - The
source
attribute of apackage
resource - Local paths in a
file
resource’ssource
attribute - The
command
of anexec
resource, unless the executable requires backslashes, e.g. cmd.exe
Backslashes Only
Backslashes MUST be used in:
- Any file paths included in the
command
of ascheduled_task
resource. - Any file paths included in the
install_options
of apackage
resource.
Using Backslashes in Double-Quoted Strings
Puppet supports two kinds of string quoting. See the reference section about strings for full details.
Strings surrounded by double quotes ("
) allow many escape sequences that begin with backslashes. (For example, \n
for a newline.) Any lone backslashes will be interpreted as part of an escape sequence.
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.
Example:
"C:\\Program Files\\PuppetLabs"
Using Backslashes in Single-Quoted Strings
Strings surrounded by single quotes 'like this'
do not interpolate variables. Only one escape sequence is permitted: \'
(a literal single quote). Line breaks within the string are interpreted as literal line breaks.
Any backslash (\
) not followed by a single quote is interpreted as a literal backslash. This means there’s no way to end a single-quoted string with a backslash; if you need to refer to a string like C:\Program Files(x86)\
, you’ll have to use a double-quote string instead.
Note: This behavior is different when the
parser
setting is set tofuture
. In the future parser, lone backslashes are literal backslashes unless followed by a single quote or another backslash. That is:
- 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.
File System Redirection (When Running 32-Bit Puppet on 64-Bit Windows)
Managing files in the C:\Windows\system32
directory can be problematic. The short version is:
- If you are using Puppet 3.7.3 or later, use the
$system32
fact whenever you need to access thesystem32
directory. Easy and reliable. - If you are using Puppet 3.7.0 through 3.7.2 but are only using architecture-appropriate packages (32-bit on 32-bit systems, and 64-bit on 64-bit systems), you can access the
system32
directory directly. As soon as is practical, you should upgrade to 3.7.3 or later, and start using the$system32
fact. - If you are using Puppet 3.7.0 through 3.7.2 and are installing the 32-bit package on 64-bit systems, continue reading.
Summary
With some combinations of Windows and Puppet versions, Windows will redirect Puppet’s access to the C:\Windows\system32
directory. If you are running Puppet in one of these configurations and are managing files in the system directory, you will need to watch out for this and compensate.
Windows | Puppet | Effects |
---|---|---|
32-bit | 32-bit | Not affected by redirection. sysnative alias doesn't exist. |
64-bit, Vista+ / 2008+ | 64-bit | |
32-bit | Redirects system32 access to SysWOW64. sysnative alias can access real system32. |
|
64-bit, 2003 R2 | 32-bit | |
64-bit, 2003 | 32-bit | Redirects system32 access to SysWOW64. Hotfix KB942589 is required to use sysnative alias. |
Note: The
sysnative
alias was added in Windows 2003 R2. 64-bit Windows 2003 requires hotfix KB942589 to use thesysnative
alias.
Details
As of Puppet 3.7, file system redirection is not an issue, as long as you are running the architecture-appropriate Puppet version on a recent version of Windows. (That is: Windows Server 2008 and higher, or Windows Vista and higher.)
However, if you are running a 32-bit version of Puppet on a 64-bit version of Windows, the File System Redirector will silently redirect all file system access of the %windir%\system32
directory to %windir%\SysWOW64
instead. This can be an issue when trying to manage files in the system directory, such as IIS configuration files.
Additionally, the ProgramFiles
environment variable resolves to C:\Program Files\
in a 64-bit native application, and C:\Program Files (x86)\
in a 32-bit process running on a 64-bit version of Windows.
There are three cases where you might be dealing with mixed Puppet/Windows architectures:
- You deliberately installed a 32-bit package on a 64-bit system, to maintain compatibility for certain modules until you’re able to update their code for 64-bit Puppet.
- You are running a 64-bit version of Windows Server 2003 or 2003 R2, which is not supported by the 64-bit Puppet installer.
- You are writing code that must support older versions of Puppet, which did not have 64-bit packages available.
Compensating for Redirection
In Puppet code, the easy way to access system32
is to use the $system32
fact, available in Puppet 3.7.3 and later. It automatically compensates for file system redirection wherever necessary.
Prior to 3.7.3, you can manually compensate. On systems affected by file system redirection, you can use the sysnative
alias in place of system32
whenever you need to access files in the system directory. (For example: C:\Windows\sysnative\inetsrv\config\application Host.config
will point to C:\Windows\system32\inetsrv\config\application Host.config
, not C:\Windows\SysWOW64\inetsrv\config\application Host.config
.)
However, note that sysnative
is only a valid path when used within a 32-bit process running on a 64-bit Windows version. It does not exist when running an architecture-appropriate Puppet package. This means you can’t simply use sysnative
everywhere to access the correct files; you’ll need to use different file paths depending on Puppet’s run environment.
Prior to 3.7.3, there’s no easy way for Puppet manifests to detect whether sysnative
is available or necessary. Authors of public modules can choose to only support 3.7.3+, or can ship a renamed version of the $system32
fact to support older versions. Private users can predict the mix of OS versions and architectures where their code will be run, and simply do the right thing for that environment.
One consideration for exec
when you can’t use $system32
is to use path =>
and set it appropriately, the first search path item first followed by others in the order you want them searched in. For instance, if you want to always use the 64-bit version of cmd.exe
you can use:
exec { '64_bit_cmd':
path => "c:\\windows\\sysnative;c:\\windows\\system32;$::path",
command => 'cmd.exe /c echo process is %PROCESSOR_ARCHITECTURE%',
}
If you always instead would rather always get a 32-bit process if it is available, you should set path more like the following:
exec { '32_bit_cmd':
path => "c:\\windows\\sysWOW64;c:\\windows\\system32;$::path",
command => 'cmd.exe /c echo process is %PROCESSOR_ARCHITECTURE%',
}
Finally, it’s possible to automatically detect which directory to use in Ruby plugin code. Do something like this example from the puppetlabs/powershell module:
commands :powershell =>
if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
else
'powershell.exe'
end
Errata
Known Issues Prior to Puppet 3.0
In Puppet 2.7, there was one additional place where backslashes were not allowed: the modulepath
setting required forward-slashes. For example: puppet apply --modulepath="Z:/path/to/my/modules" "Z:/path/to/my/site.pp"
This was fixed in Puppet 3.0 / Puppet Enterprise 3.0.