ruby-pwsh 0.10.2 → 0.11.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +16 -38
- data/README.md +29 -25
- data/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb +23 -20
- data/lib/pwsh/version.rb +1 -1
- data/lib/pwsh/windows_powershell.rb +2 -2
- data/lib/pwsh.rb +31 -34
- data/spec/acceptance/dsc/basic.rb +209 -0
- data/spec/acceptance/dsc/cim_instances.rb +81 -0
- data/spec/acceptance/dsc/class.rb +129 -0
- data/spec/acceptance/dsc/complex.rb +139 -0
- data/spec/acceptance/support/setup_winrm.ps1 +6 -0
- data/spec/exit-27.ps1 +1 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb +2084 -0
- data/spec/unit/pwsh/util_spec.rb +293 -0
- data/spec/unit/pwsh/version_spec.rb +10 -0
- data/spec/unit/pwsh/windows_powershell_spec.rb +121 -0
- data/spec/unit/pwsh_spec.rb +821 -0
- metadata +18 -22
- data/.gitattributes +0 -2
- data/.github/workflows/ci.yml +0 -109
- data/.gitignore +0 -23
- data/.pmtignore +0 -21
- data/.rspec +0 -3
- data/CHANGELOG.md +0 -204
- data/CODEOWNERS +0 -2
- data/CONTRIBUTING.md +0 -155
- data/DESIGN.md +0 -70
- data/Gemfile +0 -54
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -188
- data/design-comms.png +0 -0
- data/metadata.json +0 -82
- data/pwshlib.md +0 -92
- data/ruby-pwsh.gemspec +0 -39
data/DESIGN.md
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
# PowerShell Manager: Design and Architecture
|
2
|
-
|
3
|
-
This gem allows the use of a long-lived manager to which Ruby can send PowerShell invocations and receive the exection output.
|
4
|
-
This reduces the overhead time to execute PowerShell commands from seconds to milliseconds because each execution does not need to spin up a PowerShell process, execute a single pipeline, and tear the process down.
|
5
|
-
|
6
|
-
The manager operates by instantiating a custom PowerShell host process to which Ruby can then send commands over an IO pipe—
|
7
|
-
on Windows machines, named pipes, on Unix/Linux, Unix Domain Sockets.
|
8
|
-
|
9
|
-
## Communication Between Ruby and PowerShell Host Process
|
10
|
-
|
11
|
-
Communication between Ruby and the PowerShell host process uses binary encoded strings with a [4-byte prefix indicating how long the message is](https://en.wikipedia.org/wiki/Type-length-value).
|
12
|
-
The length prefix is a Little Endian encoded 32-bit integer.
|
13
|
-
The string being passed is always UTF-8.
|
14
|
-
|
15
|
-
Before a command string is sent to the PowerShell host process, a single 1-byte command identifier is sent—
|
16
|
-
`0` to tell the process to exit, `1` to tell the process to execute the next incoming string.
|
17
|
-
|
18
|
-
The PowerShell code to be executed is always wrapped in the following for execution to standardize behavior inside the PowerShell host process:
|
19
|
-
|
20
|
-
```powershell
|
21
|
-
$params = @{
|
22
|
-
Code = @'
|
23
|
-
#{powershell_code}
|
24
|
-
'@
|
25
|
-
TimeoutMilliseconds = #{timeout_ms}
|
26
|
-
WorkingDirectory = "#{working_dir}"
|
27
|
-
ExecEnvironmentVariables = #{exec_environment_variables}
|
28
|
-
}
|
29
|
-
|
30
|
-
Invoke-PowerShellUserCode @params
|
31
|
-
```
|
32
|
-
|
33
|
-
The code itself is placed inside a herestring and the timeout (integer), working directory (string), and environment variables (hash), if any, are passed as well.
|
34
|
-
|
35
|
-

|
36
|
-
|
37
|
-
### Output
|
38
|
-
|
39
|
-
The return from a Ruby command will always include:
|
40
|
-
|
41
|
-
+ `stdout` from the output streams, as if using `*>&1` to redirect
|
42
|
-
+ `exitcode` for the exit code of the execution; this will always be `0`, unless an exit code is specified or an exception is _thrown_.
|
43
|
-
+ `stderr` will always be an empty array.
|
44
|
-
+ `errormessage` will be the exception message of any thrown exception during execution.
|
45
|
-
+ `native_stdout` will always be nil.
|
46
|
-
|
47
|
-
#### Error Handling
|
48
|
-
|
49
|
-
Because PowerShell does not halt execution when an error is encountered, only when an terminating exception is thrown, the manager _also_ continues to execute until it encounters a terminating exception when executing commands.
|
50
|
-
This means that `Write-Error` messages will go to the stdout log but will not cause a change in the `exitcode` or populate the `errormessage` field.
|
51
|
-
Using `Throw` or any other method of generating a terminating exception _will_ set the `exitcode` to `1` and populate the `errormessage` field.
|
52
|
-
|
53
|
-
## Multiple PowerShell Host Processes
|
54
|
-
|
55
|
-
Until told otherwise, or they break, or their parent process closes, the instantiated PowerShell host processes will remain alive and waiting for further commands.
|
56
|
-
The significantly speeds up the execution of serialized commands, making continual interoperation between Ruby and PowerShell less complex for the developer leveraging this library.
|
57
|
-
|
58
|
-
In order to do this, the manager class has a class variable, `@@instances`, which contains a hash of the PowerShell hosts:
|
59
|
-
|
60
|
-
+ The key is the unique combination of options - path to the executable, flags, and additional options - passed to create the instance.
|
61
|
-
+ The value is the current state of that instance of the PowerShell host process.
|
62
|
-
|
63
|
-
If you attempt to instantiate an instance of the manager using the `instance` method, it will _first_ look to see if the specified manager and host process are already built and alive - if the manager instance does not exist or the host process is dead, _then_ it will spin up a new host process.
|
64
|
-
|
65
|
-
In test executions, standup of an instance takes around 1.5 seconds - accessing a pre-existing instance takes thousandths of a second.
|
66
|
-
|
67
|
-
## Multithreading
|
68
|
-
|
69
|
-
The manager and PowerShell host process are designed to be used single-threadedly with the PowerShell host expecting a single command and returning a single output at a time.
|
70
|
-
It does not at this time have additional guarding against being sent commands by multiple processes, but since the handles are unique IDs, this should not happen in practice.
|
data/Gemfile
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
source 'https://rubygems.org'
|
4
|
-
|
5
|
-
# Specify your gem's dependencies in pwsh.gemspec
|
6
|
-
gemspec
|
7
|
-
|
8
|
-
group :test do
|
9
|
-
gem 'ffi'
|
10
|
-
gem 'rake', '>= 10.0'
|
11
|
-
gem 'rspec', '~> 3.0'
|
12
|
-
gem 'rspec-collection_matchers', '~> 1.0'
|
13
|
-
gem 'rspec-its', '~> 1.0'
|
14
|
-
gem 'rubocop', '>= 0.77'
|
15
|
-
gem 'rubocop-rspec'
|
16
|
-
gem 'simplecov'
|
17
|
-
end
|
18
|
-
|
19
|
-
group :development do
|
20
|
-
gem 'github_changelog_generator', '~> 1.15' if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')
|
21
|
-
gem 'yard'
|
22
|
-
end
|
23
|
-
|
24
|
-
group :puppet do
|
25
|
-
gem 'pdk', '~> 1.0'
|
26
|
-
if ENV['PUPPET_GEM_VERSION']
|
27
|
-
gem 'puppet', "~> #{ENV['PUPPET_GEM_VERSION']}"
|
28
|
-
else
|
29
|
-
gem 'puppet'
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
group :pry do
|
34
|
-
gem 'fuubar'
|
35
|
-
|
36
|
-
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.4.0')
|
37
|
-
gem 'pry-byebug'
|
38
|
-
else
|
39
|
-
gem 'pry-debugger'
|
40
|
-
end
|
41
|
-
|
42
|
-
gem 'pry-stack_explorer'
|
43
|
-
end
|
44
|
-
|
45
|
-
# Evaluate Gemfile.local and ~/.gemfile if they exist
|
46
|
-
extra_gemfiles = [
|
47
|
-
"#{__FILE__}.local",
|
48
|
-
File.join(Dir.home, '.gemfile')
|
49
|
-
]
|
50
|
-
|
51
|
-
extra_gemfiles.each do |gemfile|
|
52
|
-
eval(File.read(gemfile), binding) if File.file?(gemfile) && File.readable?(gemfile) # rubocop:disable Security/Eval
|
53
|
-
end
|
54
|
-
# vim: syntax=ruby
|
data/LICENSE.txt
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
The MIT License (MIT)
|
2
|
-
|
3
|
-
Copyright (c) 2019 PuppetLabs
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
13
|
-
all copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
THE SOFTWARE.
|
data/Rakefile
DELETED
@@ -1,188 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rubocop/rake_task'
|
4
|
-
require 'fileutils'
|
5
|
-
require 'github_changelog_generator/task'
|
6
|
-
require 'open3'
|
7
|
-
require 'pwsh/version'
|
8
|
-
require 'rspec/core/rake_task'
|
9
|
-
require 'yard'
|
10
|
-
|
11
|
-
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
12
|
-
config.user = 'puppetlabs'
|
13
|
-
config.project = 'ruby-pwsh'
|
14
|
-
config.future_release = Pwsh::VERSION
|
15
|
-
config.since_tag = '0.1.0'
|
16
|
-
config.exclude_labels = ['maint']
|
17
|
-
config.header = "# Change log\n\nAll notable changes to this project will be documented in this file." \
|
18
|
-
'The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org).'
|
19
|
-
config.add_pr_wo_labels = true
|
20
|
-
config.issues = false
|
21
|
-
config.merge_prefix = '### UNCATEGORIZED PRS; GO LABEL THEM'
|
22
|
-
config.configure_sections = {
|
23
|
-
'Changed' => {
|
24
|
-
'prefix' => '### Changed',
|
25
|
-
'labels' => %w[backwards-incompatible]
|
26
|
-
},
|
27
|
-
'Added' => {
|
28
|
-
'prefix' => '### Added',
|
29
|
-
'labels' => %w[feature enhancement]
|
30
|
-
},
|
31
|
-
'Fixed' => {
|
32
|
-
'prefix' => '### Fixed',
|
33
|
-
'labels' => %w[bugfix]
|
34
|
-
}
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
RuboCop::RakeTask.new(:rubocop) do |task|
|
39
|
-
task.options = %w[-D -S -E]
|
40
|
-
end
|
41
|
-
|
42
|
-
RSpec::Core::RakeTask.new(:spec)
|
43
|
-
task default: :spec
|
44
|
-
|
45
|
-
YARD::Rake::YardocTask.new do |t|
|
46
|
-
end
|
47
|
-
|
48
|
-
# Executes a command locally.
|
49
|
-
#
|
50
|
-
# @param command [String] command to execute.
|
51
|
-
# @return [Object] the standard out stream.
|
52
|
-
def run_local_command(command)
|
53
|
-
stdout, stderr, status = Open3.capture3(command)
|
54
|
-
error_message = "Attempted to run\ncommand:'#{command}'\nstdout:#{stdout}\nstderr:#{stderr}"
|
55
|
-
raise error_message unless status.to_i.zero?
|
56
|
-
|
57
|
-
stdout
|
58
|
-
end
|
59
|
-
|
60
|
-
# Build the gem
|
61
|
-
desc 'Build the gem'
|
62
|
-
task :build do
|
63
|
-
gemspec_path = File.join(Dir.pwd, 'ruby-pwsh.gemspec')
|
64
|
-
run_local_command("bundle exec gem build '#{gemspec_path}'")
|
65
|
-
end
|
66
|
-
|
67
|
-
# Tag the repo with a version in preparation for the release
|
68
|
-
#
|
69
|
-
# @param :version [String] a semantic version to tag the code with
|
70
|
-
# @param :sha [String] the sha at which to apply the version tag
|
71
|
-
desc 'Tag the repo with a version in preparation for release'
|
72
|
-
task :tag, [:version, :sha] do |_task, args|
|
73
|
-
raise "Invalid version #{args[:version]} - must be like '1.2.3'" unless args[:version] =~ /^\d+\.\d+\.\d+$/
|
74
|
-
|
75
|
-
run_local_command('git fetch upstream')
|
76
|
-
run_local_command("git tag -a #{args[:version]} -m #{args[:version]} #{args[:sha]}")
|
77
|
-
run_local_command('git push upstream --tags')
|
78
|
-
end
|
79
|
-
|
80
|
-
# Push the built gem to RubyGems
|
81
|
-
#
|
82
|
-
# @param :path [String] optional, the full or relative path to the built gem to be pushed
|
83
|
-
desc 'Push to RubyGems'
|
84
|
-
task :push, [:path] do |_task, args|
|
85
|
-
raise 'No discoverable gem for pushing' if Dir.glob("ruby-pwsh*\.gem").empty? && args[:path].nil?
|
86
|
-
raise "No file found at specified path: '#{args[:path]}'" unless File.exist?(args[:path])
|
87
|
-
|
88
|
-
path = args[:path] || File.join(Dir.pwd, Dir.glob("ruby-pwsh*\.gem")[0])
|
89
|
-
run_local_command("bundle exec gem push #{path}")
|
90
|
-
end
|
91
|
-
|
92
|
-
desc 'Build for Puppet'
|
93
|
-
task :build_module do
|
94
|
-
actual_readme_content = File.read('README.md')
|
95
|
-
FileUtils.copy_file('pwshlib.md', 'README.md')
|
96
|
-
# Build
|
97
|
-
run_local_command('pdk build --force')
|
98
|
-
# Cleanup
|
99
|
-
File.open('README.md', 'wb') { |file| file.write(actual_readme_content) }
|
100
|
-
end
|
101
|
-
|
102
|
-
# Used in vendor_dsc_module
|
103
|
-
TAR_LONGLINK = '././@LongLink'
|
104
|
-
|
105
|
-
# Vendor a Puppetized DSC Module to spec/fixtures/modules.
|
106
|
-
#
|
107
|
-
# This is necessary because `puppet module install` fails on modules with
|
108
|
-
# long file paths, like xpsdesiredstateconfiguration
|
109
|
-
#
|
110
|
-
# @param command [String] command to execute.
|
111
|
-
# @return [Object] the standard out stream.
|
112
|
-
def vendor_dsc_module(name, version, destination)
|
113
|
-
require 'open-uri'
|
114
|
-
require 'rubygems/package'
|
115
|
-
require 'zlib'
|
116
|
-
|
117
|
-
module_uri = "https://forge.puppet.com/v3/files/dsc-#{name}-#{version}.tar.gz"
|
118
|
-
tar_gz_archive = File.expand_path("#{name}.tar.gz", ENV['TEMP'])
|
119
|
-
|
120
|
-
# Download the archive from the forge
|
121
|
-
File.open(tar_gz_archive, 'wb') do |file|
|
122
|
-
file.write(URI.open(module_uri).read) # rubocop:disable Security/Open
|
123
|
-
end
|
124
|
-
|
125
|
-
# Unzip to destination
|
126
|
-
# Taken directly from StackOverflow:
|
127
|
-
# - https://stackoverflow.com/a/19139114
|
128
|
-
Gem::Package::TarReader.new(Zlib::GzipReader.open(tar_gz_archive)) do |tar|
|
129
|
-
dest = nil
|
130
|
-
tar.each do |entry|
|
131
|
-
if entry.full_name == TAR_LONGLINK
|
132
|
-
dest = File.join(destination, entry.read.strip)
|
133
|
-
next
|
134
|
-
end
|
135
|
-
dest ||= File.join(destination, entry.full_name)
|
136
|
-
if entry.directory?
|
137
|
-
File.delete(dest) if File.file?(dest)
|
138
|
-
FileUtils.mkdir_p(dest, mode: entry.header.mode, verbose: false)
|
139
|
-
elsif entry.file?
|
140
|
-
FileUtils.rm_rf(dest) if File.directory?(dest)
|
141
|
-
File.open(dest, 'wb') do |f|
|
142
|
-
f.print(entry.read)
|
143
|
-
end
|
144
|
-
FileUtils.chmod(entry.header.mode, dest, verbose: false)
|
145
|
-
elsif entry.header.typeflag == '2' # Symlink!
|
146
|
-
File.symlink(entry.header.linkname, dest)
|
147
|
-
end
|
148
|
-
dest = nil
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# Rename folder to just the module name, as needed by Puppet
|
153
|
-
Dir.glob("#{destination}/*#{name}*").each do |existing_folder|
|
154
|
-
new_folder = File.expand_path(name, destination)
|
155
|
-
FileUtils.mv(existing_folder, new_folder)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
namespace :dsc do
|
160
|
-
namespace :acceptance do
|
161
|
-
desc 'Prep for running DSC acceptance tests'
|
162
|
-
task :spec_prep do
|
163
|
-
# Create the modules fixture folder, if needed
|
164
|
-
modules_folder = File.expand_path('spec/fixtures/modules', File.dirname(__FILE__))
|
165
|
-
FileUtils.mkdir_p(modules_folder) unless Dir.exist?(modules_folder)
|
166
|
-
# symlink the parent folder to the modules folder for puppet
|
167
|
-
symlink_path = File.expand_path('pwshlib', modules_folder)
|
168
|
-
File.symlink(File.dirname(__FILE__), symlink_path) unless Dir.exist?(symlink_path)
|
169
|
-
# Install each of the required modules for acceptance testing
|
170
|
-
# Note: This only works for modules in the dsc namespace on the forge.
|
171
|
-
puppetized_dsc_modules = [
|
172
|
-
{ name: 'powershellget', version: '2.2.5-0-1' },
|
173
|
-
{ name: 'jeadsc', version: '0.7.2-0-3' },
|
174
|
-
{ name: 'xpsdesiredstateconfiguration', version: '9.1.0-0-1' },
|
175
|
-
{ name: 'xwebadministration', version: '3.2.0-0-2' },
|
176
|
-
{ name: 'accesscontroldsc', version: '1.4.1-0-3' }
|
177
|
-
]
|
178
|
-
puppetized_dsc_modules.each do |puppet_module|
|
179
|
-
next if Dir.exist?(File.expand_path(puppet_module[:name], modules_folder))
|
180
|
-
|
181
|
-
vendor_dsc_module(puppet_module[:name], puppet_module[:version], modules_folder)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
RSpec::Core::RakeTask.new(:spec) do |t|
|
185
|
-
t.pattern = 'spec/acceptance/dsc/*.rb'
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
data/design-comms.png
DELETED
Binary file
|
data/metadata.json
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"name": "puppetlabs-pwshlib",
|
3
|
-
"version": "0.10.2",
|
4
|
-
"author": "puppetlabs",
|
5
|
-
"summary": "Provide library code for interoperating with PowerShell.",
|
6
|
-
"license": "MIT",
|
7
|
-
"source": "https://github.com/puppetlabs/ruby-pwsh",
|
8
|
-
"project_page": "https://github.com/puppetlabs/ruby-pwsh/blob/main/pwshlib.md",
|
9
|
-
"issues_url": "https://github.com/puppetlabs/ruby-pwsh/issues",
|
10
|
-
"dependencies": [
|
11
|
-
|
12
|
-
],
|
13
|
-
"operatingsystem_support": [
|
14
|
-
{
|
15
|
-
"operatingsystem": "Windows",
|
16
|
-
"operatingsystemrelease": [
|
17
|
-
"2008",
|
18
|
-
"2008 R2",
|
19
|
-
"2012",
|
20
|
-
"2012 R2",
|
21
|
-
"2016",
|
22
|
-
"2019",
|
23
|
-
"7",
|
24
|
-
"8",
|
25
|
-
"10"
|
26
|
-
]
|
27
|
-
},
|
28
|
-
{
|
29
|
-
"operatingsystem": "CentOS",
|
30
|
-
"operatingsystemrelease": [
|
31
|
-
"7",
|
32
|
-
"8"
|
33
|
-
]
|
34
|
-
},
|
35
|
-
{
|
36
|
-
"operatingsystem": "Debian",
|
37
|
-
"operatingsystemrelease": [
|
38
|
-
"8",
|
39
|
-
"9",
|
40
|
-
"10"
|
41
|
-
]
|
42
|
-
},
|
43
|
-
{
|
44
|
-
"operatingsystem": "Fedora",
|
45
|
-
"operatingsystemrelease": [
|
46
|
-
"30",
|
47
|
-
"31"
|
48
|
-
]
|
49
|
-
},
|
50
|
-
{
|
51
|
-
"operatingsystem": "OSX ",
|
52
|
-
"operatingsystemrelease": [
|
53
|
-
"10.14",
|
54
|
-
"10.15"
|
55
|
-
]
|
56
|
-
},
|
57
|
-
{
|
58
|
-
"operatingsystem": "RedHat",
|
59
|
-
"operatingsystemrelease": [
|
60
|
-
"7",
|
61
|
-
"8"
|
62
|
-
]
|
63
|
-
},
|
64
|
-
{
|
65
|
-
"operatingsystem": "Ubuntu",
|
66
|
-
"operatingsystemrelease": [
|
67
|
-
"16.04",
|
68
|
-
"18.04",
|
69
|
-
"20.04"
|
70
|
-
]
|
71
|
-
}
|
72
|
-
],
|
73
|
-
"requirements": [
|
74
|
-
{
|
75
|
-
"name": "puppet",
|
76
|
-
"version_requirement": ">= 6.0.0 < 8.0.0"
|
77
|
-
}
|
78
|
-
],
|
79
|
-
"pdk-version": "1.13.0",
|
80
|
-
"template-url": "pdk-default#1.13.0",
|
81
|
-
"template-ref": "1.13.0-0-g66e1443"
|
82
|
-
}
|
data/pwshlib.md
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
# pwshlib
|
2
|
-
|
3
|
-
This module enables you to leverage the `ruby-pwsh` gem to execute PowerShell from within your Puppet providers without having to instantiate and tear down a PowerShell process for each command called.
|
4
|
-
It supports Windows PowerShell as well as PowerShell Core - if you're running **PowerShell v3+**, this gem supports you.
|
5
|
-
|
6
|
-
The `Manager` class enables you to execute and interoperate with PowerShell from within ruby, leveraging the strengths of both languages as needed.
|
7
|
-
|
8
|
-
## Prerequisites
|
9
|
-
|
10
|
-
Include `puppetlabs-pwshlib` as a dependency in your module and you can leverage it in your providers by using a requires statement, such as in this example:
|
11
|
-
|
12
|
-
```ruby
|
13
|
-
require 'puppet/resource_api/simple_provider'
|
14
|
-
begin
|
15
|
-
require 'ruby-pwsh'
|
16
|
-
rescue LoadError
|
17
|
-
raise 'Could not load the "ruby-pwsh" library; is the dependency module puppetlabs-pwshlib installed in this environment?'
|
18
|
-
end
|
19
|
-
|
20
|
-
# Implementation for the foo type using the Resource API.
|
21
|
-
class Puppet::Provider::Foo::Foo < Puppet::ResourceApi::SimpleProvider
|
22
|
-
def get(context)
|
23
|
-
context.debug("PowerShell Path: #{Pwsh::Manager.powershell_path}")
|
24
|
-
context.debug('Returning pre-canned example data')
|
25
|
-
[
|
26
|
-
{
|
27
|
-
name: 'foo',
|
28
|
-
ensure: 'present',
|
29
|
-
},
|
30
|
-
{
|
31
|
-
name: 'bar',
|
32
|
-
ensure: 'present',
|
33
|
-
},
|
34
|
-
]
|
35
|
-
end
|
36
|
-
|
37
|
-
def create(context, name, should)
|
38
|
-
context.notice("Creating '#{name}' with #{should.inspect}")
|
39
|
-
end
|
40
|
-
|
41
|
-
def update(context, name, should)
|
42
|
-
context.notice("Updating '#{name}' with #{should.inspect}")
|
43
|
-
end
|
44
|
-
|
45
|
-
def delete(context, name)
|
46
|
-
context.notice("Deleting '#{name}'")
|
47
|
-
end
|
48
|
-
end
|
49
|
-
```
|
50
|
-
|
51
|
-
Aside from adding it as a dependency to your module metadata, you will probably also want to include it in your `.fixtures.yml` file:
|
52
|
-
|
53
|
-
```yaml
|
54
|
-
fixtures:
|
55
|
-
forge_modules:
|
56
|
-
pwshlib: "puppetlabs/pwshlib"
|
57
|
-
```
|
58
|
-
|
59
|
-
## Using the Library
|
60
|
-
|
61
|
-
Instantiating the manager can be done using some defaults:
|
62
|
-
|
63
|
-
```ruby
|
64
|
-
# Instantiate the manager for Windows PowerShell, using the default path and arguments
|
65
|
-
# Note that this takes a few seconds to instantiate.
|
66
|
-
posh = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
67
|
-
# If you try to create another manager with the same arguments it will reuse the existing one.
|
68
|
-
ps = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
69
|
-
# Note that this time the return is very fast.
|
70
|
-
# We can also use the defaults for PowerShell Core, though these only work if PowerShell is
|
71
|
-
# installed to the default paths - if it is installed anywhere else, you'll need to specify
|
72
|
-
# the full path to the pwsh executable.
|
73
|
-
pwsh = Pwsh::Manager.instance(Pwsh::Manager.pwsh_path, Pwsh::Manager.pwsh_args)
|
74
|
-
```
|
75
|
-
|
76
|
-
Execution can be done with relatively little additional work - pass the command string you want executed:
|
77
|
-
|
78
|
-
```ruby
|
79
|
-
# Instantiate the Manager:
|
80
|
-
posh = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
81
|
-
# Pretty print the output of `$PSVersionTable` to validate the version of PowerShell running
|
82
|
-
# Note that the output is a hash with a few different keys, including stdout.
|
83
|
-
Puppet.debug(posh.execute('$PSVersionTable'))
|
84
|
-
# Lets reduce the noise a little and retrieve just the version number:
|
85
|
-
# Note: We cast to a string because PSVersion is actually a Version object.
|
86
|
-
Puppet.debug(posh.execute('[String]$PSVersionTable.PSVersion'))
|
87
|
-
# We could store this output to a ruby variable if we wanted, for further use:
|
88
|
-
ps_version = posh.execute('[String]$PSVersionTable.PSVersion')[:stdout].strip
|
89
|
-
Puppet.debug("The PowerShell version of the currently running Manager is #{ps_version}")
|
90
|
-
```
|
91
|
-
|
92
|
-
For more information, please review the [online reference documentation for the gem](https://rubydoc.info/gems/ruby-pwsh).
|
data/ruby-pwsh.gemspec
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require 'pwsh/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = 'ruby-pwsh'
|
9
|
-
spec.version = Pwsh::VERSION
|
10
|
-
spec.authors = ['Puppet, Inc.']
|
11
|
-
spec.email = ['info@puppet.com']
|
12
|
-
|
13
|
-
spec.summary = 'PowerShell code manager for ruby.'
|
14
|
-
spec.description = 'PowerShell code manager for ruby.'
|
15
|
-
spec.homepage = 'https://github.com/puppetlabs/ruby-pwsh'
|
16
|
-
spec.license = 'MIT'
|
17
|
-
|
18
|
-
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
-
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
-
if spec.respond_to?(:metadata)
|
21
|
-
|
22
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
23
|
-
spec.metadata['source_code_uri'] = 'https://github.com/puppetlabs/ruby-pwsh'
|
24
|
-
spec.metadata['changelog_uri'] = 'https://github.com/puppetlabs/ruby-pwsh'
|
25
|
-
else
|
26
|
-
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
27
|
-
'public gem pushes.'
|
28
|
-
end
|
29
|
-
|
30
|
-
# Specify which files should be added to the gem when it is released.
|
31
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
32
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
33
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
34
|
-
end
|
35
|
-
|
36
|
-
spec.bindir = 'exe'
|
37
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
38
|
-
spec.require_paths = ['lib']
|
39
|
-
end
|