chef-powershell 1.0.4 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27810e07016754c9ae7553b557248f1c2f91765bbb53b265f59bfa267de12ef9
4
- data.tar.gz: e4baacfc04639cf7082da8c06ba9b8b415f8d66f5769f5675060b9e8bfc44b0a
3
+ metadata.gz: df450d23064493f0c708866adb3f5eb5e83da1e11e76238cfe1c0de60009b4c5
4
+ data.tar.gz: 30c82e0ca452f6ca72834f69e30fd59e7be7ac7e38fa4c2748e5214ecb31eb22
5
5
  SHA512:
6
- metadata.gz: 35a64b511bed8db0b95df3f0a386ff9e978eb6326e37ab3062afff1397de09f8542659744a05d77cff1b2a9e3f028436d725a7de7d6575962e5e337e365e0615
7
- data.tar.gz: 4b2df7c324ab1b8989073b69c7348d1e5a4b287e4e9400e59db0ec62ea79f08b47d4b6d712687801ad1cba2f61db72711724b8135bf0c37d95d519a8eb201952
6
+ metadata.gz: 8dfeb7613876db120ebcb32fe080d64fbe7f2b98b33d928f3d5a5300d73ed57eb3cc3e41d40c16c987af1d94e0cb99ec786792d8e733a9024c64937b84e6a9be
7
+ data.tar.gz: 43a55310801d6df2467a4f393db27e79638289d9243bbfe1c286e93d53d3d3a6ddc18977fbb43cc8960fa2879723f19dee52a765e68ef4f814113456749a9b50
data/Rakefile CHANGED
@@ -20,9 +20,7 @@
20
20
  begin
21
21
  require_relative "tasks/rspec"
22
22
  require_relative "tasks/dependencies"
23
- require_relative "tasks/docs"
24
23
  require_relative "tasks/spellcheck"
25
- require_relative "tasks/gem_build"
26
24
  require "rubocop/rake_task"
27
25
  require "rspec/core/rake_task"
28
26
  require "rubygems"
@@ -32,29 +30,6 @@ rescue LoadError => e
32
30
  puts "Skipping missing rake dep: #{e}"
33
31
  end
34
32
 
35
- desc "Builds and Copies powershell_exec related binaries from the latest built Habitat Packages"
36
- task :update_chef_powershell_dlls do
37
- raise "This task must be run on Windows since we are installing a Windows targeted package!" unless Gem.win_platform?
38
-
39
- require "mkmf"
40
- raise "Unable to locate Habitat cli. Please install Habitat cli before invoking this task!" unless find_executable "hab"
41
-
42
- sh("hab pkg build Habitat")
43
- sh("hab pkg build -R Habitat-x86")
44
-
45
- sh("hab pkg install ci/chef-powershell-shim")
46
- sh("hab pkg install ci/chef-powershell-shim-x86")
47
-
48
- x64 = `hab pkg path chef/chef-powershell-shim`.chomp.tr("\\", "/")
49
- x86 = `hab pkg path chef/chef-powershell-shim-x86`.chomp.tr("\\", "/")
50
- FileUtils.rm_rf(Dir["bin/ruby_bin_folder/AMD64/*"])
51
- FileUtils.rm_rf(Dir["bin/ruby_bin_folder/x86/*"])
52
- puts "Copying #{x64}/bin/* to chef-powershell/bin/ruby_bin_folder/AMD64"
53
- FileUtils.cp_r(Dir["#{x64}/bin/*"], "chef-powershell/bin/ruby_bin_folder/AMD64")
54
- puts "Copying #{x86}/bin/* to chef-powershell/bin/ruby_bin_folder/x86"
55
- FileUtils.cp_r(Dir["#{x86}/bin/*"], "chef-powershell/bin/ruby_bin_folder/x86")
56
- end
57
-
58
33
  desc "Chefstyle Linting and format checking"
59
34
  task :chefstyle do
60
35
  sh("bundle exec chefstyle")
@@ -1,52 +1,52 @@
1
- # frozen_string_literal: true
2
- lib = File.expand_path("lib", __dir__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- bin = File.expand_path("bin", __dir__)
5
- $LOAD_PATH.unshift(bin) unless $LOAD_PATH.include?(bin)
6
- require "chef-powershell/version"
7
-
8
- Gem::Specification.new do |spec|
9
- spec.name = "chef-powershell"
10
- spec.version = ChefPowerShell::VERSION
11
- spec.authors = ["Chef Software, Inc"]
12
- spec.email = ["oss@chef.io"]
13
-
14
- spec.summary = %q{External Chef module for accessing and utilizing PowerShell}
15
- spec.homepage = "https://github.com/chef/chef/tree/main/chef-powershell"
16
- spec.license = "Apache-2.0"
17
-
18
- spec.required_ruby_version = ">= 2.6"
19
-
20
- spec.add_runtime_dependency "ffi", "~> 1.15"
21
- spec.add_runtime_dependency "ffi-yajl", "~> 2.4"
22
-
23
- spec.metadata = {
24
- "bug_tracker_uri" => "https://github.com/chef/chef/issues",
25
- "changelog_uri" => "https://github.com/chef/chef/blob/main/CHANGELOG.md",
26
- "documentation_uri" => "https://github.com/chef/chef/tree/main/chef-powershell/README.md",
27
- "homepage_uri" => "https://github.com/chef/chef/tree/main/chef-powershell",
28
- "source_code_uri" => "https://github.com/chef/chef/tree/main/chef-powershell",
29
- }
30
-
31
- spec.require_paths = %w{lib bin}
32
-
33
- #
34
- # NOTE: DO NOT ADD RUNTIME DEPS TO OTHER CHEF ECOSYSTEM GEMS
35
- # (e.g. chef, ohai, mixlib-anything, ffi-yajl, and IN PARTICULAR NOT chef-config)
36
- #
37
- # This is so that this set of common code can be reused in any other library without
38
- # creating circular dependencies. If you find yourself wanting to do that you probably
39
- # have a helper that should go into the library you want to declare a dependency on,
40
- # or you need to create another gem that is not this one. You may also want to rub some
41
- # dependency injection on your API to invert things so that you don't have to take
42
- # a dependency on the thing you need (i.e. allow injecting a hash-like thing instead of taking
43
- # a dep on mixlib-config and then require the consumer to wire up chef-config to your
44
- # API). Same for mixlib-log and Chef::Log in general.
45
- #
46
- # ABSOLUTELY NO EXCEPTIONS
47
- #
48
- spec.bindir = "bin"
49
- spec.executables = []
50
- spec.files = %w{Rakefile LICENSE} + Dir.glob("*.gemspec") +
51
- Dir.glob("{lib,spec,bin}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
52
- end
1
+ # frozen_string_literal: true
2
+ lib = File.expand_path("lib", __dir__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ bin = File.expand_path("bin", __dir__)
5
+ $LOAD_PATH.unshift(bin) unless $LOAD_PATH.include?(bin)
6
+ require "chef-powershell/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "chef-powershell"
10
+ spec.version = ChefPowerShell::VERSION
11
+ spec.authors = ["Chef Software, Inc"]
12
+ spec.email = ["oss@chef.io"]
13
+
14
+ spec.summary = %q{External Chef module for accessing and utilizing PowerShell}
15
+ spec.homepage = "https://github.com/chef/chef-powershell-shim"
16
+ spec.license = "Apache-2.0"
17
+
18
+ spec.required_ruby_version = ">= 2.6"
19
+
20
+ spec.add_runtime_dependency "ffi", "~> 1.15"
21
+ spec.add_runtime_dependency "ffi-yajl", "~> 2.4"
22
+
23
+ spec.metadata = {
24
+ "bug_tracker_uri" => "https://github.com/chef/chef/issues",
25
+ "changelog_uri" => "https://github.com/chef/chef-powershell-shim/CHANGELOG.md",
26
+ "documentation_uri" => "https://github.com/chef/chef-powershell-shim/chef-powershell/README.md",
27
+ "homepage_uri" => "https://github.com/chef/chef/tree/main/chef-powershell",
28
+ "source_code_uri" => "https://github.com/chef/chef-powershell-shim/chef-powershell",
29
+ }
30
+
31
+ spec.require_paths = %w{lib bin}
32
+
33
+ #
34
+ # NOTE: DO NOT ADD RUNTIME DEPS TO OTHER CHEF ECOSYSTEM GEMS
35
+ # (e.g. chef, ohai, mixlib-anything, ffi-yajl, and IN PARTICULAR NOT chef-config)
36
+ #
37
+ # This is so that this set of common code can be reused in any other library without
38
+ # creating circular dependencies. If you find yourself wanting to do that you probably
39
+ # have a helper that should go into the library you want to declare a dependency on,
40
+ # or you need to create another gem that is not this one. You may also want to rub some
41
+ # dependency injection on your API to invert things so that you don't have to take
42
+ # a dependency on the thing you need (i.e. allow injecting a hash-like thing instead of taking
43
+ # a dep on mixlib-config and then require the consumer to wire up chef-config to your
44
+ # API). Same for mixlib-log and Chef::Log in general.
45
+ #
46
+ # ABSOLUTELY NO EXCEPTIONS
47
+ #
48
+ spec.bindir = "bin"
49
+ spec.executables = []
50
+ spec.files = %w{Rakefile LICENSE} + Dir.glob("*.gemspec") +
51
+ Dir.glob("{lib,spec,bin}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
52
+ end
@@ -1,27 +1,27 @@
1
- #
2
- # Author:: John McCrae (<john.mccrae@progress.com>)
3
- # Copyright:: Copyright (c) Chef Software Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
- class Chef_PowerShell
19
- class PowerShellExceptions
20
- class PowerShellCommandFailed < RuntimeError; end
21
-
22
- class JSON
23
- class EncodeError < RuntimeError; end
24
- class ParseError < RuntimeError; end
25
- end
26
- end
1
+ #
2
+ # Author:: John McCrae (<john.mccrae@progress.com>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ class Chef_PowerShell
19
+ class PowerShellExceptions
20
+ class PowerShellCommandFailed < RuntimeError; end
21
+
22
+ class JSON
23
+ class EncodeError < RuntimeError; end
24
+ class ParseError < RuntimeError; end
25
+ end
26
+ end
27
27
  end
@@ -30,7 +30,7 @@ class Chef
30
30
  def parse(source, opts = {})
31
31
  FFI_Yajl::Parser.parse(source, opts)
32
32
  rescue FFI_Yajl::ParseError => e
33
- raise Chef::PowerShellExceptions::JSON::ParseError, e.message
33
+ raise Chef_PowerShell::PowerShellExceptions::JSON::ParseError, e.message
34
34
  end
35
35
 
36
36
  def from_json(source, opts = {})
@@ -40,7 +40,7 @@ class Chef
40
40
  # you get the "must contain two octets" error). Yajl doesn't impose the
41
41
  # same limitation. For compatibility, we re-impose this condition.
42
42
  unless obj.is_a?(Hash) || obj.is_a?(Array)
43
- raise Chef::PowerShellExceptions::JSON::ParseError, "Top level JSON object must be a Hash or Array. (actual: #{obj.class})"
43
+ raise Chef_PowerShell::PowerShellExceptions::JSON::ParseError, "Top level JSON object must be a Hash or Array. (actual: #{obj.class})"
44
44
  end
45
45
 
46
46
  obj
@@ -49,7 +49,7 @@ class Chef
49
49
  def to_json(obj, opts = nil)
50
50
  FFI_Yajl::Encoder.encode(obj, opts)
51
51
  rescue FFI_Yajl::EncodeError => e
52
- raise Chef::PowerShellExceptions::JSON::EncodeError, e.message
52
+ raise Chef_PowerShell::PowerShellExceptions::JSON::EncodeError, e.message
53
53
  end
54
54
 
55
55
  def to_json_pretty(obj, opts = nil)
@@ -19,7 +19,7 @@ require "ffi" unless defined?(FFI)
19
19
  require_relative "json_compat"
20
20
  require_relative "exceptions"
21
21
  require_relative "unicode"
22
- require "chef-powershell"
22
+ # require "chef-powershell"
23
23
 
24
24
  class Chef_PowerShell
25
25
  class PowerShell
@@ -39,10 +39,9 @@ class Chef_PowerShell
39
39
  # @return [Object] output
40
40
  def initialize(script, timeout: -1)
41
41
  # This Powershell DLL source lives here: https://github.com/chef/chef-powershell-shim
42
- # Every merge into that repo triggers a Habitat build and promotion. Running
43
- # the rake :update_chef_exec_dll task in this (chef/chef) repo will pull down
44
- # the built packages and copy the binaries to chef-powershell/bin/ruby_bin_folder. Bundle install
45
- # ensures that the correct architecture binaries are installed into the path.
42
+ # Every merge into that repo triggers a Habitat build and verification process.
43
+ # There is no mechanism to build a Windows gem file. It has to be done manually running manual_gem_release.ps1
44
+ # Bundle install ensures that the correct architecture binaries are installed into the path.
46
45
  @powershell_dll = Gem.loaded_specs["chef-powershell"].full_gem_path + "/bin/ruby_bin_folder/#{ENV["PROCESSOR_ARCHITECTURE"]}/Chef.PowerShell.Wrapper.dll"
47
46
  exec(script, timeout: timeout)
48
47
  end
@@ -1,20 +1,20 @@
1
- # frozen_string_literal: true
2
- # Copyright:: Copyright (c) Chef Software Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- module ChefPowerShell
18
- CHEFPOWERSHELL_ROOT = File.expand_path("..", __dir__)
19
- VERSION = "1.0.4"
20
- end
1
+ # frozen_string_literal: true
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module ChefPowerShell
18
+ CHEFPOWERSHELL_ROOT = File.expand_path("..", __dir__)
19
+ VERSION = "1.0.7"
20
+ end
@@ -33,9 +33,9 @@ describe Chef_PowerShell::ChefPowerShell::PowerShellExec, :windows_only do
33
33
  expect(object.powershell_exec("$PSVersionTable", :powershell, timeout: -1)).to be_kind_of(Chef_PowerShell::PowerShell)
34
34
  end
35
35
 
36
- it "uses less than version 6" do
36
+ it "uses less than version 7" do
37
37
  execution = object.powershell_exec("$PSVersionTable", :powershell, timeout: -1)
38
- expect(execution.result["PSVersion"].to_s.to_i).to be < 6
38
+ expect(execution.result["PSVersion"].to_s.to_i).to be < 7
39
39
  end
40
40
  end
41
41
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-powershell
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software, Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-07 00:00:00.000000000 Z
11
+ date: 2022-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -47,7 +47,6 @@ extra_rdoc_files: []
47
47
  files:
48
48
  - LICENSE
49
49
  - Rakefile
50
- - bin/powershell/chef/chef.psm1
51
50
  - bin/ruby_bin_folder/AMD64/Chef.PowerShell.dll
52
51
  - bin/ruby_bin_folder/AMD64/Chef.Powershell.Wrapper.dll
53
52
  - bin/ruby_bin_folder/AMD64/Ijwhost.dll
@@ -667,15 +666,15 @@ files:
667
666
  - lib/chef-powershell/version.rb
668
667
  - lib/chef-powershell/wide_string.rb
669
668
  - spec/unit/powershell_exec_spec.rb
670
- homepage: https://github.com/chef/chef/tree/main/chef-powershell
669
+ homepage: https://github.com/chef/chef-powershell-shim
671
670
  licenses:
672
671
  - Apache-2.0
673
672
  metadata:
674
673
  bug_tracker_uri: https://github.com/chef/chef/issues
675
- changelog_uri: https://github.com/chef/chef/blob/main/CHANGELOG.md
676
- documentation_uri: https://github.com/chef/chef/tree/main/chef-powershell/README.md
674
+ changelog_uri: https://github.com/chef/chef-powershell-shim/CHANGELOG.md
675
+ documentation_uri: https://github.com/chef/chef-powershell-shim/chef-powershell/README.md
677
676
  homepage_uri: https://github.com/chef/chef/tree/main/chef-powershell
678
- source_code_uri: https://github.com/chef/chef/tree/main/chef-powershell
677
+ source_code_uri: https://github.com/chef/chef-powershell-shim/chef-powershell
679
678
  post_install_message:
680
679
  rdoc_options: []
681
680
  require_paths:
@@ -1,459 +0,0 @@
1
- 
2
- function Load-Win32Bindings {
3
- Add-Type -TypeDefinition @"
4
- using System;
5
- using System.Diagnostics;
6
- using System.Runtime.InteropServices;
7
-
8
- namespace Chef
9
- {
10
-
11
- [StructLayout(LayoutKind.Sequential)]
12
- public struct PROCESS_INFORMATION
13
- {
14
- public IntPtr hProcess;
15
- public IntPtr hThread;
16
- public uint dwProcessId;
17
- public uint dwThreadId;
18
- }
19
-
20
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
21
- public struct STARTUPINFO
22
- {
23
- public uint cb;
24
- public string lpReserved;
25
- public string lpDesktop;
26
- public string lpTitle;
27
- public uint dwX;
28
- public uint dwY;
29
- public uint dwXSize;
30
- public uint dwYSize;
31
- public uint dwXCountChars;
32
- public uint dwYCountChars;
33
- public uint dwFillAttribute;
34
- public STARTF dwFlags;
35
- public ShowWindow wShowWindow;
36
- public short cbReserved2;
37
- public IntPtr lpReserved2;
38
- public IntPtr hStdInput;
39
- public IntPtr hStdOutput;
40
- public IntPtr hStdError;
41
- }
42
-
43
- [StructLayout(LayoutKind.Sequential)]
44
- public struct SECURITY_ATTRIBUTES
45
- {
46
- public int length;
47
- public IntPtr lpSecurityDescriptor;
48
- public bool bInheritHandle;
49
- }
50
-
51
- [Flags]
52
- public enum CreationFlags : int
53
- {
54
- NONE = 0,
55
- DEBUG_PROCESS = 0x00000001,
56
- DEBUG_ONLY_THIS_PROCESS = 0x00000002,
57
- CREATE_SUSPENDED = 0x00000004,
58
- DETACHED_PROCESS = 0x00000008,
59
- CREATE_NEW_CONSOLE = 0x00000010,
60
- CREATE_NEW_PROCESS_GROUP = 0x00000200,
61
- CREATE_UNICODE_ENVIRONMENT = 0x00000400,
62
- CREATE_SEPARATE_WOW_VDM = 0x00000800,
63
- CREATE_SHARED_WOW_VDM = 0x00001000,
64
- CREATE_PROTECTED_PROCESS = 0x00040000,
65
- EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
66
- CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
67
- CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
68
- CREATE_DEFAULT_ERROR_MODE = 0x04000000,
69
- CREATE_NO_WINDOW = 0x08000000,
70
- }
71
-
72
- [Flags]
73
- public enum STARTF : uint
74
- {
75
- STARTF_USESHOWWINDOW = 0x00000001,
76
- STARTF_USESIZE = 0x00000002,
77
- STARTF_USEPOSITION = 0x00000004,
78
- STARTF_USECOUNTCHARS = 0x00000008,
79
- STARTF_USEFILLATTRIBUTE = 0x00000010,
80
- STARTF_RUNFULLSCREEN = 0x00000020, // ignored for non-x86 platforms
81
- STARTF_FORCEONFEEDBACK = 0x00000040,
82
- STARTF_FORCEOFFFEEDBACK = 0x00000080,
83
- STARTF_USESTDHANDLES = 0x00000100,
84
- }
85
-
86
- public enum ShowWindow : short
87
- {
88
- SW_HIDE = 0,
89
- SW_SHOWNORMAL = 1,
90
- SW_NORMAL = 1,
91
- SW_SHOWMINIMIZED = 2,
92
- SW_SHOWMAXIMIZED = 3,
93
- SW_MAXIMIZE = 3,
94
- SW_SHOWNOACTIVATE = 4,
95
- SW_SHOW = 5,
96
- SW_MINIMIZE = 6,
97
- SW_SHOWMINNOACTIVE = 7,
98
- SW_SHOWNA = 8,
99
- SW_RESTORE = 9,
100
- SW_SHOWDEFAULT = 10,
101
- SW_FORCEMINIMIZE = 11,
102
- SW_MAX = 11
103
- }
104
-
105
- public enum StandardHandle : int
106
- {
107
- Input = -10,
108
- Output = -11,
109
- Error = -12
110
- }
111
-
112
- public enum HandleFlags : int
113
- {
114
- HANDLE_FLAG_INHERIT = 0x00000001,
115
- HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002
116
- }
117
-
118
- public static class Kernel32
119
- {
120
- [DllImport("kernel32.dll", SetLastError=true)]
121
- [return: MarshalAs(UnmanagedType.Bool)]
122
- public static extern bool CreateProcess(
123
- string lpApplicationName,
124
- string lpCommandLine,
125
- ref SECURITY_ATTRIBUTES lpProcessAttributes,
126
- ref SECURITY_ATTRIBUTES lpThreadAttributes,
127
- [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles,
128
- CreationFlags dwCreationFlags,
129
- IntPtr lpEnvironment,
130
- string lpCurrentDirectory,
131
- ref STARTUPINFO lpStartupInfo,
132
- out PROCESS_INFORMATION lpProcessInformation);
133
-
134
- [DllImport("kernel32.dll", SetLastError=true)]
135
- public static extern IntPtr GetStdHandle(
136
- StandardHandle nStdHandle);
137
-
138
- [DllImport("kernel32.dll")]
139
- public static extern bool SetHandleInformation(
140
- IntPtr hObject,
141
- int dwMask,
142
- uint dwFlags);
143
-
144
- [DllImport("kernel32", SetLastError=true)]
145
- [return: MarshalAs(UnmanagedType.Bool)]
146
- public static extern bool CloseHandle(
147
- IntPtr hObject);
148
-
149
- [DllImport("kernel32", SetLastError=true)]
150
- [return: MarshalAs(UnmanagedType.Bool)]
151
- public static extern bool GetExitCodeProcess(
152
- IntPtr hProcess,
153
- out int lpExitCode);
154
-
155
- [DllImport("kernel32.dll", SetLastError = true)]
156
- public static extern bool CreatePipe(
157
- out IntPtr phReadPipe,
158
- out IntPtr phWritePipe,
159
- IntPtr lpPipeAttributes,
160
- uint nSize);
161
-
162
- [DllImport("kernel32.dll", SetLastError = true)]
163
- public static extern bool ReadFile(
164
- IntPtr hFile,
165
- [Out] byte[] lpBuffer,
166
- uint nNumberOfBytesToRead,
167
- ref int lpNumberOfBytesRead,
168
- IntPtr lpOverlapped);
169
-
170
- [DllImport("kernel32.dll", SetLastError = true)]
171
- public static extern bool PeekNamedPipe(
172
- IntPtr handle,
173
- byte[] buffer,
174
- uint nBufferSize,
175
- ref uint bytesRead,
176
- ref uint bytesAvail,
177
- ref uint BytesLeftThisMessage);
178
-
179
- public const int STILL_ACTIVE = 259;
180
- }
181
- }
182
- "@
183
- }
184
-
185
- function Run-ExecutableAndWait($AppPath, $ArgumentString) {
186
- # Use the Win32 API to create a new process and wait for it to terminate.
187
- $null = Load-Win32Bindings
188
-
189
- $si = New-Object Chef.STARTUPINFO
190
- $pi = New-Object Chef.PROCESS_INFORMATION
191
-
192
- $pSec = New-Object Chef.SECURITY_ATTRIBUTES
193
- $pSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($pSec)
194
- $pSec.bInheritHandle = $true
195
- $tSec = New-Object Chef.SECURITY_ATTRIBUTES
196
- $tSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($tSec)
197
- $tSec.bInheritHandle = $true
198
-
199
- # Create pipe for process stdout
200
- $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf($si))
201
- [System.Runtime.InteropServices.Marshal]::StructureToPtr($pSec, $ptr, $true)
202
- $hReadOut = [IntPtr]::Zero
203
- $hWriteOut = [IntPtr]::Zero
204
- $success = [Chef.Kernel32]::CreatePipe([ref] $hReadOut, [ref] $hWriteOut, $ptr, 0)
205
- if (-Not $success) {
206
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
207
- throw "Unable to create output pipe. Error code $reason."
208
- }
209
- $success = [Chef.Kernel32]::SetHandleInformation($hReadOut, [Chef.HandleFlags]::HANDLE_FLAG_INHERIT, 0)
210
- if (-Not $success) {
211
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
212
- throw "Unable to set output pipe handle information. Error code $reason."
213
- }
214
-
215
- $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
216
- $si.wShowWindow = [Chef.ShowWindow]::SW_SHOW
217
- $si.dwFlags = [Chef.STARTF]::STARTF_USESTDHANDLES
218
- $si.hStdOutput = $hWriteOut
219
- $si.hStdError = $hWriteOut
220
- $si.hStdInput = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Input)
221
-
222
- $success = [Chef.Kernel32]::CreateProcess(
223
- $AppPath,
224
- $ArgumentString,
225
- [ref] $pSec,
226
- [ref] $tSec,
227
- $true,
228
- [Chef.CreationFlags]::NONE,
229
- [IntPtr]::Zero,
230
- $pwd,
231
- [ref] $si,
232
- [ref] $pi
233
- )
234
- if (-Not $success) {
235
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
236
- throw "Unable to create process [$ArgumentString]. Error code $reason."
237
- }
238
-
239
- $buffer = New-Object byte[] 1024
240
-
241
- # Initialize reference variables
242
- $bytesRead = 0
243
- $bytesAvailable = 0
244
- $bytesLeftThisMsg = 0
245
- $global:LASTEXITCODE = [Chef.Kernel32]::STILL_ACTIVE
246
-
247
- $isActive = $true
248
- while ($isActive) {
249
- $success = [Chef.Kernel32]::GetExitCodeProcess($pi.hProcess, [ref] $global:LASTEXITCODE)
250
- if (-Not $success) {
251
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
252
- throw "Process exit code unavailable. Error code $reason."
253
- }
254
-
255
- $success = [Chef.Kernel32]::PeekNamedPipe(
256
- $hReadOut,
257
- $null,
258
- $buffer.Length,
259
- [ref] $bytesRead,
260
- [ref] $bytesAvailable,
261
- [ref] $bytesLeftThisMsg
262
- )
263
- if (-Not $success) {
264
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
265
- throw "Output pipe unavailable for peeking. Error code $reason."
266
- }
267
-
268
- if ($bytesRead -gt 0) {
269
- while ([Chef.Kernel32]::ReadFile($hReadOut, $buffer, $buffer.Length, [ref] $bytesRead, 0)) {
270
- $output = [Text.Encoding]::UTF8.GetString($buffer, 0, $bytesRead)
271
- if ($output) {
272
- $output
273
- }
274
- if ($bytesRead -lt $buffer.Length) {
275
- # Partial buffer indicating the end of stream, break out of ReadFile loop
276
- # ReadFile will block until:
277
- # The number of bytes requested is read.
278
- # A write operation completes on the write end of the pipe.
279
- # An asynchronous handle is being used and the read is occurring asynchronously.
280
- # An error occurs.
281
- break
282
- }
283
- }
284
- } else {
285
- # For some reason, you can't read from the read-end of the read-pipe before the write end has started
286
- # to write. Otherwise the process just blocks forever and never returns from the read. So we peek
287
- # at the pipe until there is something. But don't peek too eagerly. This is stupid stupid stupid.
288
- # There must be a way to do this without having to peek at a pipe first but I have not found it.
289
- #
290
- # Note to the future intrepid soul who wants to fix this:
291
- # 0) This is related to unreasonable CPU usage by the wrapper PS script on a 1 VCPU VM (either Hyper-V
292
- # or VirtualBox) running a consumer Windows SKU (Windows 10 for example...). Test it there.
293
- # 1) Maybe this entire script is unnecessary and the bugs mentioned below have been fixed or don't need
294
- # to be supported.
295
- # 2) The server and consumer windows schedulers have different defaults. I had a hard time reproducing
296
- # any issue on a win 2008 on win 2012 server default setup. See the "foreground application scheduler
297
- # priority" setting to see if it's relevant.
298
- # 3) This entire endeavor is silly anyway - why are we reimplementing process forking all over? Maybe try
299
- # to get the folks above to accept patches instead of extending this crazy script.
300
- Start-Sleep -s 1
301
- # Start-Sleep -m 100
302
- }
303
-
304
- if ($global:LASTEXITCODE -ne [Chef.Kernel32]::STILL_ACTIVE) {
305
- $isActive = $false
306
- }
307
- }
308
-
309
- # Cleanup handles
310
- $success = [Chef.Kernel32]::CloseHandle($pi.hProcess)
311
- if (-Not $success) {
312
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
313
- throw "Unable to release process handle. Error code $reason."
314
- }
315
- $success = [Chef.Kernel32]::CloseHandle($pi.hThread)
316
- if (-Not $success) {
317
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
318
- throw "Unable to release thread handle. Error code $reason."
319
- }
320
- $success = [Chef.Kernel32]::CloseHandle($hWriteOut)
321
- if (-Not $success) {
322
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
323
- throw "Unable to release output write handle. Error code $reason."
324
- }
325
- $success = [Chef.Kernel32]::CloseHandle($hReadOut)
326
- if (-Not $success) {
327
- $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
328
- throw "Unable to release output read handle. Error code $reason."
329
- }
330
- [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
331
- }
332
-
333
- function Get-ScriptDirectory {
334
- if (!$PSScriptRoot) {
335
- $Invocation = (Get-Variable MyInvocation -Scope 1).Value
336
- $PSScriptRoot = Split-Path $Invocation.MyCommand.Path
337
- }
338
- $PSScriptRoot
339
- }
340
-
341
- function Run-RubyCommand($command, $argList) {
342
- # This method exists to take the given list of arguments and get it past ruby's command-line
343
- # interpreter unscathed and untampered. See https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L1582
344
- # for a list of transformations that ruby attempts to perform with your command-line arguments
345
- # before passing it onto a script. The most important task is to defeat the globbing
346
- # and wild-card expansion that ruby performs. Note that ruby does not use MSVCRT's argc/argv
347
- # and deliberately reparses the raw command-line instead.
348
- #
349
- # To stop ruby from interpreting command-line arguments as globs, they need to be enclosed in '
350
- # Ruby doesn't allow any escape characters inside '. This unfortunately prevents us from sending
351
- # any strings which themselves contain '. Ruby does allow multi-fragment arguments though.
352
- # "foo bar"'baz qux'123"foo" is interpreted as 1 argument because there are no un-escaped
353
- # whitespace there. The argument would be interpreted as the string "foo barbaz qux123foo".
354
- # This lets us escape ' characters by exiting the ' quoted string, injecting a "'" fragment and
355
- # then resuming the ' quoted string again.
356
- #
357
- # In the process of defeating ruby, one must also defeat the helpfulness of powershell.
358
- # When arguments come into this method, the standard PS rules for interpreting cmdlet arguments
359
- # apply. When using & (call operator) and providing an array of arguments, powershell (verified
360
- # on PS 4.0 on Windows Server 2012R2) will not evaluate them but (contrary to documentation),
361
- # it will still marginally interpret them. The behavior of PS 5.0 seems to be different but
362
- # ignore that for now. If any of the provided arguments has a space in it, powershell checks
363
- # the first and last character to ensure that they are " characters (and that's all it checks).
364
- # If they are not, it will blindly surround that argument with " characters. It won't do this
365
- # operation if no space is present, even if other special characters are present. If it notices
366
- # leading and trailing " characters, it won't actually check to see if there are other "
367
- # characters in the string. Since PS 5.0 changes this behavior, we could consider using the --%
368
- # "stop screwing up my arguments" operator, which is available since PS 3.0. When encountered
369
- # --% indicates that the rest of line is to be sent literally... except if the parser encounters
370
- # %FOO% cmd style environment variables. Because reasons. And there is no way to escape the
371
- # % character in *any* waym shape or form.
372
- # https://connect.microsoft.com/PowerShell/feedback/details/376207/executing-commands-which-require-quotes-and-variables-is-practically-impossible
373
- #
374
- # In case you think that you're either reading this incorrectly or that I'm full of shit, here
375
- # are some examples. These use EchoArgs.exe from the PowerShell Community Extensions package.
376
- # I have not included the argument parsing output from EchoArgs.exe to prevent confusing you with
377
- # more details about MSVCRT's parsing algorithm.
378
- #
379
- # $x = "foo '' bar `"baz`""
380
- # & EchoArgs @($x, $x)
381
- # Command line:
382
- # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" "foo '' bar "baz"" "foo '' bar "baz""
383
- #
384
- # $x = "abc'123'nospace`"lol`"!!!"
385
- # & EchoArgs @($x, $x)
386
- # Command line:
387
- # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" abc'123'nospace"lol"!!! abc'123'nospace"lol"!!!
388
- #
389
- # $x = "`"`"Look ma! Tonnes of spaces! 'foo' 'bar'`"`""
390
- # & EchoArgs @($x, $x)
391
- # Command line:
392
- # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" ""Look ma! Tonnes of spaces! 'foo' 'bar'"" ""Look ma! Tonnes of spaces! 'foo' 'bar'""
393
- #
394
- # Given all this, we can now device a strategy to work around all these immensely helpful, well
395
- # documented and useful tools by looking at each incoming argument, escaping any ' characters
396
- # with a '"'"' sequence, surrounding each argument with ' & joining them with a space separating
397
- # them.
398
- # There is another bug (https://bugs.ruby-lang.org/issues/11142) that causes ruby to mangle any
399
- # "" two-character double quote sequence but since we always emit our strings inside ' except for
400
- # ' characters, this should be ok. Just remember that an argument '' should get translated to
401
- # ''"'"''"'"'' on the command line. If those intervening empty ''s are not present, the presence
402
- # of "" will cause ruby to mangle that argument.
403
- $transformedList = $argList | foreach { "'" + ( $_ -replace "'","'`"'`"'" ) + "'" }
404
- $fortifiedArgString = $transformedList -join ' '
405
-
406
- # Use the correct embedded ruby path. We'll be deployed at a path that looks like
407
- # [C:\opscode or some other prefix]\chef\modules\chef
408
- $ruby = Join-Path (Get-ScriptDirectory) "..\..\embedded\bin\ruby.exe"
409
- $commandPath = Join-Path (Get-ScriptDirectory) "..\..\bin\$command"
410
-
411
- Run-ExecutableAndWait $ruby """$ruby"" '$commandPath' $fortifiedArgString"
412
- }
413
-
414
-
415
- function chef-apply {
416
- Run-RubyCommand 'chef-apply' $args
417
- }
418
-
419
- function chef-client {
420
- Run-RubyCommand 'chef-client' $args
421
- }
422
-
423
- function chef-service-manager {
424
- Run-RubyCommand 'chef-service-manager' $args
425
- }
426
-
427
- function chef-shell {
428
- Run-RubyCommand 'chef-shell' $args
429
- }
430
-
431
- function chef-solo {
432
- Run-RubyCommand 'chef-solo' $args
433
- }
434
-
435
- function chef-windows-service {
436
- Run-RubyCommand 'chef-windows-service' $args
437
- }
438
-
439
- function knife {
440
- Run-RubyCommand 'knife' $args
441
- }
442
-
443
- Export-ModuleMember -function chef-apply
444
- Export-ModuleMember -function chef-client
445
- Export-ModuleMember -function chef-service-manager
446
- Export-ModuleMember -function chef-shell
447
- Export-ModuleMember -function chef-solo
448
- Export-ModuleMember -function chef-windows-service
449
- Export-ModuleMember -function knife
450
-
451
- # To debug this module, uncomment the line below
452
- # Export-ModuleMember -function Run-RubyCommand
453
-
454
- # Then run the following to reload the module. Use puts_argv as a helpful debug executable.
455
- # Remove-Module chef
456
- # Import-Module chef
457
- # "puts ARGV" | Out-File C:\opscode\chef\bin\puts_args -Encoding ASCII
458
- # Copy-Item C:\opscode\chef\bin\ohai.bat C:\opscode\chef\bin\puts_args.bat
459
- # Run-RubyCommand puts_args 'Here' "are" some '"very interesting"' 'arguments[to]' "`"try out`""