Skip to content

Commit 9276de6

Browse files
committed
Merge pull request puppetlabs#102 from glennsarti/stable
Merge branch 'master' into stable
2 parents 39b9844 + 287bf5a commit 9276de6

File tree

14 files changed

+1328
-65
lines changed

14 files changed

+1328
-65
lines changed

.fixtures.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fixtures:
2+
forge_modules:
3+
symlinks:
4+
"powershell": "#{source_dir}"

.sync.yml

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,6 @@
66
env: PUPPET_GEM_VERSION="3.0.0"
77
Gemfile:
88
supports_windows: true
9-
required:
10-
':development':
11-
- gem: rake
12-
- gem: rspec
13-
version: '~>3.0.0'
14-
- gem: puppet-lint
15-
- gem: puppetlabs_spec_helper
16-
version: '~>0.10.3'
17-
- gem: puppet_facts
18-
- gem: mocha
19-
version: '~>0.10.5'
20-
':system_tests':
21-
- gem: beaker
22-
- gem: beaker-rspec
23-
- gem: beaker-puppet_install_helper
249
Rakefile:
2510
unmanaged: true
2611
spec/spec_helper.rb:
@@ -30,7 +15,7 @@ appveyor.yml:
3015
- PUPPET_GEM_VERSION: 3.0.0
3116
RUBY_VER: 193
3217
test_script:
33-
- 'bundle exec rspec spec/unit -fd -b'
18+
- 'bundle exec rspec spec/unit spec/integration -fd -b'
3419
MAINTAINERS.md:
3520
maintainers:
3621
- "Puppet Windows Team `windows |at| puppet |dot| com`"
@@ -40,4 +25,4 @@ NOTICE:
4025
begin: 2013
4126
- name: 'Puppet, Inc.'
4227
begin: 2013
43-
end: 'latest'
28+
end: 'latest'

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
##2015-05-17 - Supported Release 2.0.0
2+
###Summary
3+
4+
Major release with performance improvements
5+
6+
Removed support for Windows Server 2003
7+
8+
###Features
9+
- Major performance improvement by sharing a single powershell session instead of creating a new powershell session per command
10+
- Security improvement as scripts are not stored on the filesystem temporarily
11+
12+
###Bug Fixes
13+
- Updated test suites with later versions
14+
- Documentation cleanup
15+
116
##2015-12-08 - Supported Release 1.0.6
217
###Summary
318

Gemfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,17 @@ end
3737

3838
group :development do
3939
gem 'rake', :require => false
40-
gem 'rspec', '~>3.0.0', :require => false
40+
gem 'rspec', '~>3.0', :require => false
4141
gem 'puppet-lint', :require => false
4242
gem 'puppetlabs_spec_helper', '~>0.10.3', :require => false
4343
gem 'puppet_facts', :require => false
4444
gem 'mocha', '~>0.10.5', :require => false
45+
gem 'pry', :require => false
4546
end
4647

4748
group :system_tests do
48-
gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '~> 2.20')
4949
gem 'beaker-rspec', *location_for(ENV['BEAKER_RSPEC_VERSION'] || '~> 5.1')
50+
gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '~> 2.20')
5051
gem 'beaker-puppet_install_helper', :require => false
5152
end
5253

README.md

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
##Overview
1616

17-
This module adds a new exec provider capable of executing PowerShell commands.
17+
This module adds a new exec provider capable of executing PowerShell commands.
1818

1919
##Module Description
2020

@@ -29,50 +29,53 @@ This module requires PowerShell to be installed and the `powershell.exe` to be a
2929

3030
The powershell module adapts the Puppet [exec](http://docs.puppet.com/references/stable/type.html#exec) resource to run PowerShell commands. To get started, simply install the module and declare 'powershell' in `provider` with the applicable command.
3131

32-
~~~
33-
exec { 'RESOURCENAME':
34-
command => '$(SOMECOMMAND)',
35-
provider => powershell,
36-
}
32+
~~~ puppet
33+
exec { 'RESOURCENAME':
34+
command => '$(SOMECOMMAND)',
35+
provider => powershell,
36+
}
3737
~~~
3838

3939
##Usage
4040

41-
When using `exec` resources with the `powershell` provider, the `command` parameter must be single-quoted to prevent Puppet from interpolating `$(..)`.
41+
When using `exec` resources with the `powershell` provider, the `command` parameter must be single-quoted to prevent Puppet from interpolating `$(..)`.
4242

4343
For instance, if you wanted to rename the Guest account:
4444

45-
~~~
46-
exec { 'rename-guest':
47-
command => '$(Get-WMIObject Win32_UserAccount -Filter "Name=\'guest\'").Rename("new-guest")',
48-
unless => 'if (Get-WmiObject Win32_UserAccount -Filter "Name=\'guest\'") { exit 1 }',
49-
provider => powershell,
50-
}
45+
~~~ puppet
46+
exec { 'rename-guest':
47+
command => '$(Get-WMIObject Win32_UserAccount -Filter "Name=\'guest\'").Rename("new-guest")',
48+
unless => 'if (Get-WmiObject Win32_UserAccount -Filter "Name=\'guest\'") { exit 1 }',
49+
provider => powershell,
50+
}
5151
~~~
5252

5353
Note that the example uses the `unless` parameter to make the resource idempotent. The `command` is only executed if the Guest account does not exist, as indicated by `unless` returning 0.
5454

5555
**Note:** PowerShell variables (e.g. `$_`), must be escaped in Puppet manifests either using backslashes or single quotes.
5656

57-
Alternatively, you can put the PowerShell code for the `command`, `onlyif`, and `unless` parameters into separate templates and then invoke the template function in the resource.
57+
Alternatively, you can put the PowerShell code for the `command`, `onlyif`, and `unless` parameters into separate files and then invoke the file function in the resource. Templates and the `template()` function could also be used here if the PowerShell scripts need to have access to variables from Puppet.
5858

59-
~~~
59+
~~~ puppet
6060
exec { 'rename-guest':
61-
command => template('guest/rename-guest.ps1'),
62-
onlyif => template('guest/guest-exists.ps1'),
61+
command => file('guest/rename-guest.ps1'),
62+
onlyif => file('guest/guest-exists.ps1'),
6363
provider => powershell,
6464
logoutput => true,
6565
}
6666
~~~
6767

68-
Each template is a PowerShell script.
68+
Each file is a PowerShell script that should be in the module's `files/` folder.
6969

70-
~~~
70+
For example, here is the script at: `guest/files/rename-guest.ps1`
71+
72+
~~~ powershell
7173
$obj = $(Get-WMIObject Win32_UserAccount -Filter "Name='Guest'")
7274
$obj.Rename("OtherGuest")
7375
~~~
7476

75-
This has the added benefit of not requiring escaping '$' in the PowerShell code.
77+
This has the added benefit of not requiring escaping '$' in the PowerShell code. Note that the files need to have DOS linefeeds or they will not work as expected. One tool for converting UNIX linefeeds to DOS linefeeds is [unix2dos](http://freecode.com/projects/dos2unix).
78+
7679

7780
##Reference
7881

@@ -101,7 +104,7 @@ Defines whether to log command output in addition to logging the exit code. If y
101104
Runs the exec only if the command returns 0. Valid options: String. Default: Undefined.
102105

103106
#####`path`
104-
Specifies the search path used for command execution. Valid options: String of the path, an array, or a semicolon-separated list. Default: Undefined.
107+
Specifies the search path used for command execution. Valid options: String of the path, an array, or a semicolon-separated list. Default: Undefined.
105108

106109
#####`refresh`
107110
Refreshes the command. Valid options: String. Default: Undefined.
@@ -117,7 +120,7 @@ Sets the maximum time in seconds that the command should take. Valid options: Nu
117120

118121
#####`tries`
119122
Determines the number of times execution of the command should be attempted. Valid options: Number or a string representation of a number. Default: '1'.
120-
123+
121124
#####`try_sleep`
122125
Specifies the time to sleep in seconds between `tries`. Valid options: Number or a string representation of a number. Default: Undefined.
123126

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ build: off
3030
test_script:
3131
- bundle exec puppet -V
3232
- ruby -v
33-
- bundle exec rspec spec/unit -fd -b
33+
- bundle exec rspec spec/unit spec/integration -fd -b
3434
notifications:
3535
- provider: Email
3636
to:

lib/puppet/provider/exec/powershell.rb

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'puppet/provider/exec'
2+
require_relative '../../../puppet_x/puppetlabs/powershell_manager'
23

34
Puppet::Type.type(:exec).provide :powershell, :parent => Puppet::Provider::Exec do
45
confine :operatingsystem => :windows
@@ -25,17 +26,65 @@
2526
}
2627
EOT
2728

29+
POWERSHELL_UPGRADE_MSG = <<-UPGRADE
30+
The current Puppet version is outdated and uses a library that was
31+
previously necessary on the current Ruby verison to support a colored console.
32+
33+
Unfortunately this library prevents the PowerShell module from using a shared
34+
PowerShell process to dramatically improve the performance of resource
35+
application.
36+
37+
To enable these improvements, it is suggested to upgrade to any x64 version of
38+
Puppet (including 3.x), or to a Puppet version newer than 3.x.
39+
UPGRADE
40+
41+
def self.upgrade_message
42+
Puppet.warning POWERSHELL_UPGRADE_MSG if !@upgrade_warning_issued
43+
@upgrade_warning_issued = true
44+
end
45+
46+
def self.powershell_args
47+
ps_args = ['-NoProfile', '-NonInteractive', '-NoLogo', '-ExecutionPolicy', 'Bypass', '-Command']
48+
ps_args << '-' if PuppetX::PowerShell::PowerShellManager.supported?
49+
ps_args
50+
end
51+
52+
def ps_manager
53+
PuppetX::PowerShell::PowerShellManager.instance("#{command(:powershell)} #{self.class.powershell_args.join(' ')}")
54+
end
55+
2856
def run(command, check = false)
29-
write_script(command) do |native_path|
30-
# Ideally, we could keep a handle open on the temp file in this
31-
# process (to prevent TOCTOU attacks), and execute powershell
32-
# with -File <path>. But powershell complains that it can't open
33-
# the file for exclusive access. If we close the handle, then an
34-
# attacker could modify the file before we invoke powershell. So
35-
# we redirect powershell's stdin to read from the file. Current
36-
# versions of Windows use per-user temp directories with strong
37-
# permissions, but I'd rather not make (poor) assumptions.
38-
return super("cmd.exe /c \"\"#{native_path(command(:powershell))}\" #{args} -Command - < \"#{native_path}\"\"", check)
57+
if !PuppetX::PowerShell::PowerShellManager.supported?
58+
self.class.upgrade_message
59+
write_script(command) do |native_path|
60+
# Ideally, we could keep a handle open on the temp file in this
61+
# process (to prevent TOCTOU attacks), and execute powershell
62+
# with -File <path>. But powershell complains that it can't open
63+
# the file for exclusive access. If we close the handle, then an
64+
# attacker could modify the file before we invoke powershell. So
65+
# we redirect powershell's stdin to read from the file. Current
66+
# versions of Windows use per-user temp directories with strong
67+
# permissions, but I'd rather not make (poor) assumptions.
68+
return super("cmd.exe /c \"\"#{native_path(command(:powershell))}\" #{legacy_args} -Command - < \"#{native_path}\"\"", check)
69+
end
70+
else
71+
result = ps_manager.execute(command)
72+
73+
stdout = result[:stdout]
74+
stderr = result[:stderr]
75+
exit_code = result[:exitcode]
76+
77+
unless stderr.nil?
78+
stderr.each do |er|
79+
er.each { |e| Puppet.debug "STDERR: #{e.chop}" } unless er.empty?
80+
end
81+
end
82+
83+
Puppet.debug "STDERR: #{result[:errormessage]}" unless result[:errormessage].nil?
84+
85+
output = Puppet::Util::Execution::ProcessOutput.new(stdout.to_s || '', exit_code)
86+
87+
return output, output
3988
end
4089
end
4190

@@ -63,7 +112,7 @@ def native_path(path)
63112
end
64113
end
65114

66-
def args
115+
def legacy_args
67116
'-NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass'
68117
end
69118
end

0 commit comments

Comments
 (0)