module Puppet::Util::Windows::Process

Constants

CREATE_NO_WINDOW

docs.microsoft.com/en-us/windows/desktop/ProcThread/process-creation-flags

ERROR_NO_SUCH_PRIVILEGE
MAX_PATH_LENGTH

docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation

PROCESS_QUERY_INFORMATION

docs.microsoft.com/en-us/windows/desktop/ProcThread/process-security-and-access-rights

TOKEN_ALL_ACCESS
TOKEN_QUERY
WAIT_INTERVAL
WAIT_TIMEOUT

Public Class Methods

elevated_security?() click to toggle source

Returns whether or not the owner of the current process is running with elevated security privileges.

Only supported on Windows Vista or later.

    # File lib/puppet/util/windows/process.rb
253 def elevated_security?
254   # default / pre-Vista
255   elevated = false
256   handle = nil
257 
258   begin
259     handle = get_current_process
260     open_process_token(handle, TOKEN_QUERY) do |token_handle|
261       get_token_information(token_handle, :TokenElevation) do |token_info|
262         token_elevation = parse_token_information_as_token_elevation(token_info)
263         # TokenIsElevated member of the TOKEN_ELEVATION struct
264         elevated = token_elevation[:TokenIsElevated] != 0
265       end
266     end
267 
268     elevated
269   rescue Puppet::Util::Windows::Error => e
270     raise e if e.code != ERROR_NO_SUCH_PRIVILEGE
271   ensure
272     FFI::WIN32.CloseHandle(handle) if handle
273   end
274 end
execute(command, arguments, stdin, stdout, stderr) click to toggle source
   # File lib/puppet/util/windows/process.rb
19 def execute(command, arguments, stdin, stdout, stderr)
20   create_args = {
21     :command_line => command,
22     :startup_info => {
23       :stdin => stdin,
24       :stdout => stdout,
25       :stderr => stderr
26     },
27     :close_handles => false,
28   }
29   if arguments[:suppress_window]
30     create_args[:creation_flags] = CREATE_NO_WINDOW
31   end
32   if arguments[:cwd]
33     create_args[:cwd] = arguments[:cwd]
34   end
35   Process.create(create_args)
36 end
get_current_process() click to toggle source
   # File lib/puppet/util/windows/process.rb
62 def get_current_process
63   # this pseudo-handle does not require closing per MSDN docs
64   GetCurrentProcess()
65 end
get_environment_strings() click to toggle source

Returns a hash of the current environment variables encoded as UTF-8 The memory block returned from GetEnvironmentStringsW is double-null terminated and the vars are paired as below; Var1=Value10 Var2=Value20 VarX=ValueX00 Note - Some env variable names start with '=' and are excluded from the return value Note - The env_ptr MUST be freed using the FreeEnvironmentStringsW function Note - There is no technical limitation to the size of the environment block returned.

However a practical limit of 64K is used as no single environment variable can exceed 32KB
    # File lib/puppet/util/windows/process.rb
306 def get_environment_strings
307   env_ptr = GetEnvironmentStringsW()
308 
309   # pass :invalid => :replace to the Ruby String#encode to use replacement characters
310   pairs = env_ptr.read_arbitrary_wide_string_up_to(65534, :double_null, { :invalid => :replace })
311     .split(?\x00)
312     .reject { |env_str| env_str.nil? || env_str.empty? || env_str[0] == '=' }
313     .reject do |env_str|
314       # reject any string containing the Unicode replacement character
315       if env_str.include?("\uFFFD")
316         Puppet.warning(_("Discarding environment variable %{string} which contains invalid bytes") % { string: env_str })
317         true
318       end
319     end
320     .map { |env_pair| env_pair.split('=', 2) }
321   Hash[ pairs ]
322 ensure
323   if env_ptr && ! env_ptr.null?
324     if FreeEnvironmentStringsW(env_ptr) == FFI::WIN32_FALSE
325       Puppet.debug "FreeEnvironmentStringsW memory leak"
326     end
327   end
328 end
get_process_image_name_by_pid(pid) click to toggle source
    # File lib/puppet/util/windows/process.rb
123 def get_process_image_name_by_pid(pid)
124   image_name = String.new
125 
126   Puppet::Util::Windows::Security.with_privilege(Puppet::Util::Windows::Security::SE_DEBUG_NAME) do
127     open_process(PROCESS_QUERY_INFORMATION, false, pid) do |phandle|
128       FFI::MemoryPointer.new(:dword, 1) do |exe_name_length_ptr|
129         # UTF is 2 bytes/char:
130         max_chars = MAX_PATH_LENGTH + 1
131         exe_name_length_ptr.write_dword(max_chars)
132         FFI::MemoryPointer.new(:wchar, max_chars) do |exe_name_ptr|
133           use_win32_path_format = 0
134           result = QueryFullProcessImageNameW(phandle, use_win32_path_format, exe_name_ptr, exe_name_length_ptr)
135           if result == FFI::WIN32_FALSE
136             raise Puppet::Util::Windows::Error.new(
137                     "QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, " +
138                     "exe_name_ptr, #{max_chars}")
139           end
140           image_name = exe_name_ptr.read_wide_string(exe_name_length_ptr.read_dword)
141         end
142       end
143     end
144   end
145 
146   image_name
147 end
get_system_default_ui_language() click to toggle source
    # File lib/puppet/util/windows/process.rb
350 def get_system_default_ui_language
351   GetSystemDefaultUILanguage()
352 end
get_token_information(token_handle, token_information) { |token_information_buf| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
171 def get_token_information(token_handle, token_information, &block)
172   # to determine buffer size
173   FFI::MemoryPointer.new(:dword, 1) do |return_length_ptr|
174     result = GetTokenInformation(token_handle, token_information, nil, 0, return_length_ptr)
175     return_length = return_length_ptr.read_dword
176 
177     if return_length <= 0
178       raise Puppet::Util::Windows::Error.new(
179         "GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr})")
180     end
181 
182     # re-call API with properly sized buffer for all results
183     FFI::MemoryPointer.new(return_length) do |token_information_buf|
184       result = GetTokenInformation(token_handle, token_information,
185         token_information_buf, return_length, return_length_ptr)
186 
187       if result == FFI::WIN32_FALSE
188         raise Puppet::Util::Windows::Error.new(
189           "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " +
190             "#{return_length}, #{return_length_ptr})")
191       end
192 
193       yield token_information_buf
194     end
195   end
196 
197   # GetTokenInformation buffer has been cleaned up by this point, nothing to return
198   nil
199 end
lookup_privilege_value(name, system_name = '') { |luid| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
150 def lookup_privilege_value(name, system_name = '', &block)
151   FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
152     result = LookupPrivilegeValueW(
153       wide_string(system_name),
154       wide_string(name.to_s),
155       luid_ptr
156       )
157 
158     if result == FFI::WIN32_FALSE
159       raise Puppet::Util::Windows::Error.new(
160         "LookupPrivilegeValue(#{system_name}, #{name}, #{luid_ptr})")
161     end
162 
163     yield LUID.new(luid_ptr)
164   end
165 
166   # the underlying MemoryPointer for LUID is cleaned up by this point
167   nil
168 end
open_process(desired_access, inherit_handle, process_id) { |phandle| ... } click to toggle source
   # File lib/puppet/util/windows/process.rb
68 def open_process(desired_access, inherit_handle, process_id, &block)
69   phandle = nil
70   inherit = inherit_handle ? FFI::WIN32_TRUE : FFI::WIN32_FALSE
71   begin
72     phandle = OpenProcess(desired_access, inherit, process_id)
73     if phandle == FFI::Pointer::NULL_HANDLE
74       raise Puppet::Util::Windows::Error.new(
75         "OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process_id})")
76     end
77 
78     yield phandle
79   ensure
80     FFI::WIN32.CloseHandle(phandle) if phandle
81   end
82 
83   # phandle has had CloseHandle called against it, so nothing to return
84   nil
85 end
open_process_token(handle, desired_access) { |token_handle = read_handle| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
 88 def open_process_token(handle, desired_access, &block)
 89   token_handle = nil
 90   begin
 91     FFI::MemoryPointer.new(:handle, 1) do |token_handle_ptr|
 92       result = OpenProcessToken(handle, desired_access, token_handle_ptr)
 93       if result == FFI::WIN32_FALSE
 94         raise Puppet::Util::Windows::Error.new(
 95           "OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{token_handle_ptr})")
 96       end
 97 
 98       yield token_handle = token_handle_ptr.read_handle
 99     end
100 
101     token_handle
102   ensure
103     FFI::WIN32.CloseHandle(token_handle) if token_handle
104   end
105 
106   # token_handle has had CloseHandle called against it, so nothing to return
107   nil
108 end
parse_token_information_as_token_elevation(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
218 def parse_token_information_as_token_elevation(token_information_buf)
219   TOKEN_ELEVATION.new(token_information_buf)
220 end
parse_token_information_as_token_privileges(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
202 def parse_token_information_as_token_privileges(token_information_buf)
203   raw_privileges = TOKEN_PRIVILEGES.new(token_information_buf)
204   privileges = { :count => raw_privileges[:PrivilegeCount], :privileges => [] }
205 
206   offset = token_information_buf + TOKEN_PRIVILEGES.offset_of(:Privileges)
207   privilege_ptr = FFI::Pointer.new(LUID_AND_ATTRIBUTES, offset)
208 
209   # extract each instance of LUID_AND_ATTRIBUTES
210   0.upto(privileges[:count] - 1) do |i|
211     privileges[:privileges] <<  LUID_AND_ATTRIBUTES.new(privilege_ptr[i])
212   end
213 
214   privileges
215 end
set_environment_variable(name, val) click to toggle source
    # File lib/puppet/util/windows/process.rb
331 def set_environment_variable(name, val)
332   raise Puppet::Util::Windows::Error(_('environment variable name must not be nil or empty')) if ! name || name.empty?
333 
334   FFI::MemoryPointer.from_string_to_wide_string(name) do |name_ptr|
335     if (val.nil?)
336       if SetEnvironmentVariableW(name_ptr, FFI::MemoryPointer::NULL) == FFI::WIN32_FALSE
337         raise Puppet::Util::Windows::Error.new(_("Failed to remove environment variable: %{name}") % { name: name })
338       end
339     else
340       FFI::MemoryPointer.from_string_to_wide_string(val) do |val_ptr|
341         if SetEnvironmentVariableW(name_ptr, val_ptr) == FFI::WIN32_FALSE
342           raise Puppet::Util::Windows::Error.new(_("Failed to set environment variable: %{name}") % { name: name })
343         end
344       end
345     end
346   end
347 end
supports_elevated_security?() click to toggle source

Returns whether or not the OS has the ability to set elevated token information.

Returns true on Windows Vista or later, otherwise false

    # File lib/puppet/util/windows/process.rb
360 def supports_elevated_security?
361   windows_major_version >= 6
362 end
wait_process(handle) click to toggle source
   # File lib/puppet/util/windows/process.rb
39 def wait_process(handle)
40   while WaitForSingleObject(handle, WAIT_INTERVAL) == WAIT_TIMEOUT
41     sleep(0)
42   end
43 
44   exit_status = -1
45   FFI::MemoryPointer.new(:dword, 1) do |exit_status_ptr|
46     if GetExitCodeProcess(handle, exit_status_ptr) == FFI::WIN32_FALSE
47       raise Puppet::Util::Windows::Error.new(_("Failed to get child process exit code"))
48     end
49     exit_status = exit_status_ptr.read_dword
50 
51     # $CHILD_STATUS is not set when calling win32/process Process.create
52     # and since it's read-only, we can't set it. But we can execute a
53     # a shell that simply returns the desired exit status, which has the
54     # desired effect.
55     %x{#{ENV['COMSPEC']} /c exit #{exit_status}}
56   end
57 
58   exit_status
59 end
windows_major_version() click to toggle source
    # File lib/puppet/util/windows/process.rb
277 def windows_major_version
278   ver = 0
279 
280   FFI::MemoryPointer.new(OSVERSIONINFO.size) do |os_version_ptr|
281     os_version = OSVERSIONINFO.new(os_version_ptr)
282     os_version[:dwOSVersionInfoSize] = OSVERSIONINFO.size
283 
284     result = GetVersionExW(os_version_ptr)
285 
286     if result == FFI::WIN32_FALSE
287       raise Puppet::Util::Windows::Error.new(_("GetVersionEx failed"))
288     end
289 
290     ver = os_version[:dwMajorVersion]
291   end
292 
293   ver
294 end
with_process_token(access) { |token_handle| ... } click to toggle source

Execute a block with the current process token

    # File lib/puppet/util/windows/process.rb
112 def with_process_token(access, &block)
113   handle = get_current_process
114   open_process_token(handle, access) do |token_handle|
115     yield token_handle
116   end
117 
118   # all handles have been closed, so nothing to safely return
119   nil
120 end

Private Instance Methods

elevated_security?() click to toggle source

Returns whether or not the owner of the current process is running with elevated security privileges.

Only supported on Windows Vista or later.

    # File lib/puppet/util/windows/process.rb
253 def elevated_security?
254   # default / pre-Vista
255   elevated = false
256   handle = nil
257 
258   begin
259     handle = get_current_process
260     open_process_token(handle, TOKEN_QUERY) do |token_handle|
261       get_token_information(token_handle, :TokenElevation) do |token_info|
262         token_elevation = parse_token_information_as_token_elevation(token_info)
263         # TokenIsElevated member of the TOKEN_ELEVATION struct
264         elevated = token_elevation[:TokenIsElevated] != 0
265       end
266     end
267 
268     elevated
269   rescue Puppet::Util::Windows::Error => e
270     raise e if e.code != ERROR_NO_SUCH_PRIVILEGE
271   ensure
272     FFI::WIN32.CloseHandle(handle) if handle
273   end
274 end
execute(command, arguments, stdin, stdout, stderr) click to toggle source
   # File lib/puppet/util/windows/process.rb
19 def execute(command, arguments, stdin, stdout, stderr)
20   create_args = {
21     :command_line => command,
22     :startup_info => {
23       :stdin => stdin,
24       :stdout => stdout,
25       :stderr => stderr
26     },
27     :close_handles => false,
28   }
29   if arguments[:suppress_window]
30     create_args[:creation_flags] = CREATE_NO_WINDOW
31   end
32   if arguments[:cwd]
33     create_args[:cwd] = arguments[:cwd]
34   end
35   Process.create(create_args)
36 end
get_current_process() click to toggle source
   # File lib/puppet/util/windows/process.rb
62 def get_current_process
63   # this pseudo-handle does not require closing per MSDN docs
64   GetCurrentProcess()
65 end
get_environment_strings() click to toggle source

Returns a hash of the current environment variables encoded as UTF-8 The memory block returned from GetEnvironmentStringsW is double-null terminated and the vars are paired as below; Var1=Value10 Var2=Value20 VarX=ValueX00 Note - Some env variable names start with '=' and are excluded from the return value Note - The env_ptr MUST be freed using the FreeEnvironmentStringsW function Note - There is no technical limitation to the size of the environment block returned.

However a practical limit of 64K is used as no single environment variable can exceed 32KB
    # File lib/puppet/util/windows/process.rb
306 def get_environment_strings
307   env_ptr = GetEnvironmentStringsW()
308 
309   # pass :invalid => :replace to the Ruby String#encode to use replacement characters
310   pairs = env_ptr.read_arbitrary_wide_string_up_to(65534, :double_null, { :invalid => :replace })
311     .split(?\x00)
312     .reject { |env_str| env_str.nil? || env_str.empty? || env_str[0] == '=' }
313     .reject do |env_str|
314       # reject any string containing the Unicode replacement character
315       if env_str.include?("\uFFFD")
316         Puppet.warning(_("Discarding environment variable %{string} which contains invalid bytes") % { string: env_str })
317         true
318       end
319     end
320     .map { |env_pair| env_pair.split('=', 2) }
321   Hash[ pairs ]
322 ensure
323   if env_ptr && ! env_ptr.null?
324     if FreeEnvironmentStringsW(env_ptr) == FFI::WIN32_FALSE
325       Puppet.debug "FreeEnvironmentStringsW memory leak"
326     end
327   end
328 end
get_process_image_name_by_pid(pid) click to toggle source
    # File lib/puppet/util/windows/process.rb
123 def get_process_image_name_by_pid(pid)
124   image_name = String.new
125 
126   Puppet::Util::Windows::Security.with_privilege(Puppet::Util::Windows::Security::SE_DEBUG_NAME) do
127     open_process(PROCESS_QUERY_INFORMATION, false, pid) do |phandle|
128       FFI::MemoryPointer.new(:dword, 1) do |exe_name_length_ptr|
129         # UTF is 2 bytes/char:
130         max_chars = MAX_PATH_LENGTH + 1
131         exe_name_length_ptr.write_dword(max_chars)
132         FFI::MemoryPointer.new(:wchar, max_chars) do |exe_name_ptr|
133           use_win32_path_format = 0
134           result = QueryFullProcessImageNameW(phandle, use_win32_path_format, exe_name_ptr, exe_name_length_ptr)
135           if result == FFI::WIN32_FALSE
136             raise Puppet::Util::Windows::Error.new(
137                     "QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, " +
138                     "exe_name_ptr, #{max_chars}")
139           end
140           image_name = exe_name_ptr.read_wide_string(exe_name_length_ptr.read_dword)
141         end
142       end
143     end
144   end
145 
146   image_name
147 end
get_system_default_ui_language() click to toggle source
    # File lib/puppet/util/windows/process.rb
350 def get_system_default_ui_language
351   GetSystemDefaultUILanguage()
352 end
get_token_information(token_handle, token_information) { |token_information_buf| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
171 def get_token_information(token_handle, token_information, &block)
172   # to determine buffer size
173   FFI::MemoryPointer.new(:dword, 1) do |return_length_ptr|
174     result = GetTokenInformation(token_handle, token_information, nil, 0, return_length_ptr)
175     return_length = return_length_ptr.read_dword
176 
177     if return_length <= 0
178       raise Puppet::Util::Windows::Error.new(
179         "GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr})")
180     end
181 
182     # re-call API with properly sized buffer for all results
183     FFI::MemoryPointer.new(return_length) do |token_information_buf|
184       result = GetTokenInformation(token_handle, token_information,
185         token_information_buf, return_length, return_length_ptr)
186 
187       if result == FFI::WIN32_FALSE
188         raise Puppet::Util::Windows::Error.new(
189           "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " +
190             "#{return_length}, #{return_length_ptr})")
191       end
192 
193       yield token_information_buf
194     end
195   end
196 
197   # GetTokenInformation buffer has been cleaned up by this point, nothing to return
198   nil
199 end
lookup_privilege_value(name, system_name = '') { |luid| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
150 def lookup_privilege_value(name, system_name = '', &block)
151   FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
152     result = LookupPrivilegeValueW(
153       wide_string(system_name),
154       wide_string(name.to_s),
155       luid_ptr
156       )
157 
158     if result == FFI::WIN32_FALSE
159       raise Puppet::Util::Windows::Error.new(
160         "LookupPrivilegeValue(#{system_name}, #{name}, #{luid_ptr})")
161     end
162 
163     yield LUID.new(luid_ptr)
164   end
165 
166   # the underlying MemoryPointer for LUID is cleaned up by this point
167   nil
168 end
open_process(desired_access, inherit_handle, process_id) { |phandle| ... } click to toggle source
   # File lib/puppet/util/windows/process.rb
68 def open_process(desired_access, inherit_handle, process_id, &block)
69   phandle = nil
70   inherit = inherit_handle ? FFI::WIN32_TRUE : FFI::WIN32_FALSE
71   begin
72     phandle = OpenProcess(desired_access, inherit, process_id)
73     if phandle == FFI::Pointer::NULL_HANDLE
74       raise Puppet::Util::Windows::Error.new(
75         "OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process_id})")
76     end
77 
78     yield phandle
79   ensure
80     FFI::WIN32.CloseHandle(phandle) if phandle
81   end
82 
83   # phandle has had CloseHandle called against it, so nothing to return
84   nil
85 end
open_process_token(handle, desired_access) { |token_handle = read_handle| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
 88 def open_process_token(handle, desired_access, &block)
 89   token_handle = nil
 90   begin
 91     FFI::MemoryPointer.new(:handle, 1) do |token_handle_ptr|
 92       result = OpenProcessToken(handle, desired_access, token_handle_ptr)
 93       if result == FFI::WIN32_FALSE
 94         raise Puppet::Util::Windows::Error.new(
 95           "OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{token_handle_ptr})")
 96       end
 97 
 98       yield token_handle = token_handle_ptr.read_handle
 99     end
100 
101     token_handle
102   ensure
103     FFI::WIN32.CloseHandle(token_handle) if token_handle
104   end
105 
106   # token_handle has had CloseHandle called against it, so nothing to return
107   nil
108 end
parse_token_information_as_token_elevation(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
218 def parse_token_information_as_token_elevation(token_information_buf)
219   TOKEN_ELEVATION.new(token_information_buf)
220 end
parse_token_information_as_token_privileges(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
202 def parse_token_information_as_token_privileges(token_information_buf)
203   raw_privileges = TOKEN_PRIVILEGES.new(token_information_buf)
204   privileges = { :count => raw_privileges[:PrivilegeCount], :privileges => [] }
205 
206   offset = token_information_buf + TOKEN_PRIVILEGES.offset_of(:Privileges)
207   privilege_ptr = FFI::Pointer.new(LUID_AND_ATTRIBUTES, offset)
208 
209   # extract each instance of LUID_AND_ATTRIBUTES
210   0.upto(privileges[:count] - 1) do |i|
211     privileges[:privileges] <<  LUID_AND_ATTRIBUTES.new(privilege_ptr[i])
212   end
213 
214   privileges
215 end
set_environment_variable(name, val) click to toggle source
    # File lib/puppet/util/windows/process.rb
331 def set_environment_variable(name, val)
332   raise Puppet::Util::Windows::Error(_('environment variable name must not be nil or empty')) if ! name || name.empty?
333 
334   FFI::MemoryPointer.from_string_to_wide_string(name) do |name_ptr|
335     if (val.nil?)
336       if SetEnvironmentVariableW(name_ptr, FFI::MemoryPointer::NULL) == FFI::WIN32_FALSE
337         raise Puppet::Util::Windows::Error.new(_("Failed to remove environment variable: %{name}") % { name: name })
338       end
339     else
340       FFI::MemoryPointer.from_string_to_wide_string(val) do |val_ptr|
341         if SetEnvironmentVariableW(name_ptr, val_ptr) == FFI::WIN32_FALSE
342           raise Puppet::Util::Windows::Error.new(_("Failed to set environment variable: %{name}") % { name: name })
343         end
344       end
345     end
346   end
347 end
supports_elevated_security?() click to toggle source

Returns whether or not the OS has the ability to set elevated token information.

Returns true on Windows Vista or later, otherwise false

    # File lib/puppet/util/windows/process.rb
360 def supports_elevated_security?
361   windows_major_version >= 6
362 end
wait_process(handle) click to toggle source
   # File lib/puppet/util/windows/process.rb
39 def wait_process(handle)
40   while WaitForSingleObject(handle, WAIT_INTERVAL) == WAIT_TIMEOUT
41     sleep(0)
42   end
43 
44   exit_status = -1
45   FFI::MemoryPointer.new(:dword, 1) do |exit_status_ptr|
46     if GetExitCodeProcess(handle, exit_status_ptr) == FFI::WIN32_FALSE
47       raise Puppet::Util::Windows::Error.new(_("Failed to get child process exit code"))
48     end
49     exit_status = exit_status_ptr.read_dword
50 
51     # $CHILD_STATUS is not set when calling win32/process Process.create
52     # and since it's read-only, we can't set it. But we can execute a
53     # a shell that simply returns the desired exit status, which has the
54     # desired effect.
55     %x{#{ENV['COMSPEC']} /c exit #{exit_status}}
56   end
57 
58   exit_status
59 end
windows_major_version() click to toggle source
    # File lib/puppet/util/windows/process.rb
277 def windows_major_version
278   ver = 0
279 
280   FFI::MemoryPointer.new(OSVERSIONINFO.size) do |os_version_ptr|
281     os_version = OSVERSIONINFO.new(os_version_ptr)
282     os_version[:dwOSVersionInfoSize] = OSVERSIONINFO.size
283 
284     result = GetVersionExW(os_version_ptr)
285 
286     if result == FFI::WIN32_FALSE
287       raise Puppet::Util::Windows::Error.new(_("GetVersionEx failed"))
288     end
289 
290     ver = os_version[:dwMajorVersion]
291   end
292 
293   ver
294 end
with_process_token(access) { |token_handle| ... } click to toggle source

Execute a block with the current process token

    # File lib/puppet/util/windows/process.rb
112 def with_process_token(access, &block)
113   handle = get_current_process
114   open_process_token(handle, access) do |token_handle|
115     yield token_handle
116   end
117 
118   # all handles have been closed, so nothing to safely return
119   nil
120 end