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
252 def elevated_security?
253   # default / pre-Vista
254   elevated = false
255   handle = nil
256 
257   begin
258     handle = get_current_process
259     open_process_token(handle, TOKEN_QUERY) do |token_handle|
260       get_token_information(token_handle, :TokenElevation) do |token_info|
261         token_elevation = parse_token_information_as_token_elevation(token_info)
262         # TokenIsElevated member of the TOKEN_ELEVATION struct
263         elevated = token_elevation[:TokenIsElevated] != 0
264       end
265     end
266 
267     elevated
268   rescue Puppet::Util::Windows::Error => e
269     raise e if e.code != ERROR_NO_SUCH_PRIVILEGE
270   ensure
271     FFI::WIN32.CloseHandle(handle) if handle
272   end
273 end
execute(command, arguments, stdin, stdout, stderr) click to toggle source
   # File lib/puppet/util/windows/process.rb
18 def execute(command, arguments, stdin, stdout, stderr)
19   create_args = {
20     :command_line => command,
21     :startup_info => {
22       :stdin => stdin,
23       :stdout => stdout,
24       :stderr => stderr
25     },
26     :close_handles => false,
27   }
28   if arguments[:suppress_window]
29     create_args[:creation_flags] = CREATE_NO_WINDOW
30   end
31   if arguments[:cwd]
32     create_args[:cwd] = arguments[:cwd]
33   end
34   Process.create(create_args)
35 end
get_current_process() click to toggle source
   # File lib/puppet/util/windows/process.rb
61 def get_current_process
62   # this pseudo-handle does not require closing per MSDN docs
63   GetCurrentProcess()
64 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
305 def get_environment_strings
306   env_ptr = GetEnvironmentStringsW()
307 
308   # pass :invalid => :replace to the Ruby String#encode to use replacement characters
309   pairs = env_ptr.read_arbitrary_wide_string_up_to(65534, :double_null, { :invalid => :replace })
310     .split(?\x00)
311     .reject { |env_str| env_str.nil? || env_str.empty? || env_str[0] == '=' }
312     .reject do |env_str|
313       # reject any string containing the Unicode replacement character
314       if env_str.include?("\uFFFD")
315         Puppet.warning(_("Discarding environment variable %{string} which contains invalid bytes") % { string: env_str })
316         true
317       end
318     end
319     .map { |env_pair| env_pair.split('=', 2) }
320   Hash[ pairs ]
321 ensure
322   if env_ptr && ! env_ptr.null?
323     if FreeEnvironmentStringsW(env_ptr) == FFI::WIN32_FALSE
324       Puppet.debug "FreeEnvironmentStringsW memory leak"
325     end
326   end
327 end
get_process_image_name_by_pid(pid) click to toggle source
    # File lib/puppet/util/windows/process.rb
122 def get_process_image_name_by_pid(pid)
123   image_name = ""
124 
125   Puppet::Util::Windows::Security.with_privilege(Puppet::Util::Windows::Security::SE_DEBUG_NAME) do
126     open_process(PROCESS_QUERY_INFORMATION, false, pid) do |phandle|
127       FFI::MemoryPointer.new(:dword, 1) do |exe_name_length_ptr|
128         # UTF is 2 bytes/char:
129         max_chars = MAX_PATH_LENGTH + 1
130         exe_name_length_ptr.write_dword(max_chars)
131         FFI::MemoryPointer.new(:wchar, max_chars) do |exe_name_ptr|
132           use_win32_path_format = 0
133           result = QueryFullProcessImageNameW(phandle, use_win32_path_format, exe_name_ptr, exe_name_length_ptr)
134           if result == FFI::WIN32_FALSE
135             raise Puppet::Util::Windows::Error.new(
136                     "QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, " +
137                     "exe_name_ptr, #{max_chars}")
138           end
139           image_name = exe_name_ptr.read_wide_string(exe_name_length_ptr.read_dword)
140         end
141       end
142     end
143   end
144 
145   image_name
146 end
get_system_default_ui_language() click to toggle source
    # File lib/puppet/util/windows/process.rb
349 def get_system_default_ui_language
350   GetSystemDefaultUILanguage()
351 end
get_token_information(token_handle, token_information) { |token_information_buf| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
170 def get_token_information(token_handle, token_information, &block)
171   # to determine buffer size
172   FFI::MemoryPointer.new(:dword, 1) do |return_length_ptr|
173     result = GetTokenInformation(token_handle, token_information, nil, 0, return_length_ptr)
174     return_length = return_length_ptr.read_dword
175 
176     if return_length <= 0
177       raise Puppet::Util::Windows::Error.new(
178         "GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr})")
179     end
180 
181     # re-call API with properly sized buffer for all results
182     FFI::MemoryPointer.new(return_length) do |token_information_buf|
183       result = GetTokenInformation(token_handle, token_information,
184         token_information_buf, return_length, return_length_ptr)
185 
186       if result == FFI::WIN32_FALSE
187         raise Puppet::Util::Windows::Error.new(
188           "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " +
189             "#{return_length}, #{return_length_ptr})")
190       end
191 
192       yield token_information_buf
193     end
194   end
195 
196   # GetTokenInformation buffer has been cleaned up by this point, nothing to return
197   nil
198 end
lookup_privilege_value(name, system_name = '') { |luid| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
149 def lookup_privilege_value(name, system_name = '', &block)
150   FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
151     result = LookupPrivilegeValueW(
152       wide_string(system_name),
153       wide_string(name.to_s),
154       luid_ptr
155       )
156 
157     if result == FFI::WIN32_FALSE
158       raise Puppet::Util::Windows::Error.new(
159         "LookupPrivilegeValue(#{system_name}, #{name}, #{luid_ptr})")
160     end
161 
162     yield LUID.new(luid_ptr)
163   end
164 
165   # the underlying MemoryPointer for LUID is cleaned up by this point
166   nil
167 end
open_process(desired_access, inherit_handle, process_id) { |phandle| ... } click to toggle source
   # File lib/puppet/util/windows/process.rb
67 def open_process(desired_access, inherit_handle, process_id, &block)
68   phandle = nil
69   inherit = inherit_handle ? FFI::WIN32_TRUE : FFI::WIN32_FALSE
70   begin
71     phandle = OpenProcess(desired_access, inherit, process_id)
72     if phandle == FFI::Pointer::NULL_HANDLE
73       raise Puppet::Util::Windows::Error.new(
74         "OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process_id})")
75     end
76 
77     yield phandle
78   ensure
79     FFI::WIN32.CloseHandle(phandle) if phandle
80   end
81 
82   # phandle has had CloseHandle called against it, so nothing to return
83   nil
84 end
open_process_token(handle, desired_access) { |token_handle = read_handle| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
 87 def open_process_token(handle, desired_access, &block)
 88   token_handle = nil
 89   begin
 90     FFI::MemoryPointer.new(:handle, 1) do |token_handle_ptr|
 91       result = OpenProcessToken(handle, desired_access, token_handle_ptr)
 92       if result == FFI::WIN32_FALSE
 93         raise Puppet::Util::Windows::Error.new(
 94           "OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{token_handle_ptr})")
 95       end
 96 
 97       yield token_handle = token_handle_ptr.read_handle
 98     end
 99 
100     token_handle
101   ensure
102     FFI::WIN32.CloseHandle(token_handle) if token_handle
103   end
104 
105   # token_handle has had CloseHandle called against it, so nothing to return
106   nil
107 end
parse_token_information_as_token_elevation(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
217 def parse_token_information_as_token_elevation(token_information_buf)
218   TOKEN_ELEVATION.new(token_information_buf)
219 end
parse_token_information_as_token_privileges(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
201 def parse_token_information_as_token_privileges(token_information_buf)
202   raw_privileges = TOKEN_PRIVILEGES.new(token_information_buf)
203   privileges = { :count => raw_privileges[:PrivilegeCount], :privileges => [] }
204 
205   offset = token_information_buf + TOKEN_PRIVILEGES.offset_of(:Privileges)
206   privilege_ptr = FFI::Pointer.new(LUID_AND_ATTRIBUTES, offset)
207 
208   # extract each instance of LUID_AND_ATTRIBUTES
209   0.upto(privileges[:count] - 1) do |i|
210     privileges[:privileges] <<  LUID_AND_ATTRIBUTES.new(privilege_ptr[i])
211   end
212 
213   privileges
214 end
set_environment_variable(name, val) click to toggle source
    # File lib/puppet/util/windows/process.rb
330 def set_environment_variable(name, val)
331   raise Puppet::Util::Windows::Error(_('environment variable name must not be nil or empty')) if ! name || name.empty?
332 
333   FFI::MemoryPointer.from_string_to_wide_string(name) do |name_ptr|
334     if (val.nil?)
335       if SetEnvironmentVariableW(name_ptr, FFI::MemoryPointer::NULL) == FFI::WIN32_FALSE
336         raise Puppet::Util::Windows::Error.new(_("Failed to remove environment variable: %{name}") % { name: name })
337       end
338     else
339       FFI::MemoryPointer.from_string_to_wide_string(val) do |val_ptr|
340         if SetEnvironmentVariableW(name_ptr, val_ptr) == FFI::WIN32_FALSE
341           raise Puppet::Util::Windows::Error.new(_("Failed to set environment variable: %{name}") % { name: name })
342         end
343       end
344     end
345   end
346 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
359 def supports_elevated_security?
360   windows_major_version >= 6
361 end
wait_process(handle) click to toggle source
   # File lib/puppet/util/windows/process.rb
38 def wait_process(handle)
39   while WaitForSingleObject(handle, WAIT_INTERVAL) == WAIT_TIMEOUT
40     sleep(0)
41   end
42 
43   exit_status = -1
44   FFI::MemoryPointer.new(:dword, 1) do |exit_status_ptr|
45     if GetExitCodeProcess(handle, exit_status_ptr) == FFI::WIN32_FALSE
46       raise Puppet::Util::Windows::Error.new(_("Failed to get child process exit code"))
47     end
48     exit_status = exit_status_ptr.read_dword
49 
50     # $CHILD_STATUS is not set when calling win32/process Process.create
51     # and since it's read-only, we can't set it. But we can execute a
52     # a shell that simply returns the desired exit status, which has the
53     # desired effect.
54     %x{#{ENV['COMSPEC']} /c exit #{exit_status}}
55   end
56 
57   exit_status
58 end
windows_major_version() click to toggle source
    # File lib/puppet/util/windows/process.rb
276 def windows_major_version
277   ver = 0
278 
279   FFI::MemoryPointer.new(OSVERSIONINFO.size) do |os_version_ptr|
280     os_version = OSVERSIONINFO.new(os_version_ptr)
281     os_version[:dwOSVersionInfoSize] = OSVERSIONINFO.size
282 
283     result = GetVersionExW(os_version_ptr)
284 
285     if result == FFI::WIN32_FALSE
286       raise Puppet::Util::Windows::Error.new(_("GetVersionEx failed"))
287     end
288 
289     ver = os_version[:dwMajorVersion]
290   end
291 
292   ver
293 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
111 def with_process_token(access, &block)
112   handle = get_current_process
113   open_process_token(handle, access) do |token_handle|
114     yield token_handle
115   end
116 
117   # all handles have been closed, so nothing to safely return
118   nil
119 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
252 def elevated_security?
253   # default / pre-Vista
254   elevated = false
255   handle = nil
256 
257   begin
258     handle = get_current_process
259     open_process_token(handle, TOKEN_QUERY) do |token_handle|
260       get_token_information(token_handle, :TokenElevation) do |token_info|
261         token_elevation = parse_token_information_as_token_elevation(token_info)
262         # TokenIsElevated member of the TOKEN_ELEVATION struct
263         elevated = token_elevation[:TokenIsElevated] != 0
264       end
265     end
266 
267     elevated
268   rescue Puppet::Util::Windows::Error => e
269     raise e if e.code != ERROR_NO_SUCH_PRIVILEGE
270   ensure
271     FFI::WIN32.CloseHandle(handle) if handle
272   end
273 end
execute(command, arguments, stdin, stdout, stderr) click to toggle source
   # File lib/puppet/util/windows/process.rb
18 def execute(command, arguments, stdin, stdout, stderr)
19   create_args = {
20     :command_line => command,
21     :startup_info => {
22       :stdin => stdin,
23       :stdout => stdout,
24       :stderr => stderr
25     },
26     :close_handles => false,
27   }
28   if arguments[:suppress_window]
29     create_args[:creation_flags] = CREATE_NO_WINDOW
30   end
31   if arguments[:cwd]
32     create_args[:cwd] = arguments[:cwd]
33   end
34   Process.create(create_args)
35 end
get_current_process() click to toggle source
   # File lib/puppet/util/windows/process.rb
61 def get_current_process
62   # this pseudo-handle does not require closing per MSDN docs
63   GetCurrentProcess()
64 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
305 def get_environment_strings
306   env_ptr = GetEnvironmentStringsW()
307 
308   # pass :invalid => :replace to the Ruby String#encode to use replacement characters
309   pairs = env_ptr.read_arbitrary_wide_string_up_to(65534, :double_null, { :invalid => :replace })
310     .split(?\x00)
311     .reject { |env_str| env_str.nil? || env_str.empty? || env_str[0] == '=' }
312     .reject do |env_str|
313       # reject any string containing the Unicode replacement character
314       if env_str.include?("\uFFFD")
315         Puppet.warning(_("Discarding environment variable %{string} which contains invalid bytes") % { string: env_str })
316         true
317       end
318     end
319     .map { |env_pair| env_pair.split('=', 2) }
320   Hash[ pairs ]
321 ensure
322   if env_ptr && ! env_ptr.null?
323     if FreeEnvironmentStringsW(env_ptr) == FFI::WIN32_FALSE
324       Puppet.debug "FreeEnvironmentStringsW memory leak"
325     end
326   end
327 end
get_process_image_name_by_pid(pid) click to toggle source
    # File lib/puppet/util/windows/process.rb
122 def get_process_image_name_by_pid(pid)
123   image_name = ""
124 
125   Puppet::Util::Windows::Security.with_privilege(Puppet::Util::Windows::Security::SE_DEBUG_NAME) do
126     open_process(PROCESS_QUERY_INFORMATION, false, pid) do |phandle|
127       FFI::MemoryPointer.new(:dword, 1) do |exe_name_length_ptr|
128         # UTF is 2 bytes/char:
129         max_chars = MAX_PATH_LENGTH + 1
130         exe_name_length_ptr.write_dword(max_chars)
131         FFI::MemoryPointer.new(:wchar, max_chars) do |exe_name_ptr|
132           use_win32_path_format = 0
133           result = QueryFullProcessImageNameW(phandle, use_win32_path_format, exe_name_ptr, exe_name_length_ptr)
134           if result == FFI::WIN32_FALSE
135             raise Puppet::Util::Windows::Error.new(
136                     "QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, " +
137                     "exe_name_ptr, #{max_chars}")
138           end
139           image_name = exe_name_ptr.read_wide_string(exe_name_length_ptr.read_dword)
140         end
141       end
142     end
143   end
144 
145   image_name
146 end
get_system_default_ui_language() click to toggle source
    # File lib/puppet/util/windows/process.rb
349 def get_system_default_ui_language
350   GetSystemDefaultUILanguage()
351 end
get_token_information(token_handle, token_information) { |token_information_buf| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
170 def get_token_information(token_handle, token_information, &block)
171   # to determine buffer size
172   FFI::MemoryPointer.new(:dword, 1) do |return_length_ptr|
173     result = GetTokenInformation(token_handle, token_information, nil, 0, return_length_ptr)
174     return_length = return_length_ptr.read_dword
175 
176     if return_length <= 0
177       raise Puppet::Util::Windows::Error.new(
178         "GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr})")
179     end
180 
181     # re-call API with properly sized buffer for all results
182     FFI::MemoryPointer.new(return_length) do |token_information_buf|
183       result = GetTokenInformation(token_handle, token_information,
184         token_information_buf, return_length, return_length_ptr)
185 
186       if result == FFI::WIN32_FALSE
187         raise Puppet::Util::Windows::Error.new(
188           "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " +
189             "#{return_length}, #{return_length_ptr})")
190       end
191 
192       yield token_information_buf
193     end
194   end
195 
196   # GetTokenInformation buffer has been cleaned up by this point, nothing to return
197   nil
198 end
lookup_privilege_value(name, system_name = '') { |luid| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
149 def lookup_privilege_value(name, system_name = '', &block)
150   FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
151     result = LookupPrivilegeValueW(
152       wide_string(system_name),
153       wide_string(name.to_s),
154       luid_ptr
155       )
156 
157     if result == FFI::WIN32_FALSE
158       raise Puppet::Util::Windows::Error.new(
159         "LookupPrivilegeValue(#{system_name}, #{name}, #{luid_ptr})")
160     end
161 
162     yield LUID.new(luid_ptr)
163   end
164 
165   # the underlying MemoryPointer for LUID is cleaned up by this point
166   nil
167 end
open_process(desired_access, inherit_handle, process_id) { |phandle| ... } click to toggle source
   # File lib/puppet/util/windows/process.rb
67 def open_process(desired_access, inherit_handle, process_id, &block)
68   phandle = nil
69   inherit = inherit_handle ? FFI::WIN32_TRUE : FFI::WIN32_FALSE
70   begin
71     phandle = OpenProcess(desired_access, inherit, process_id)
72     if phandle == FFI::Pointer::NULL_HANDLE
73       raise Puppet::Util::Windows::Error.new(
74         "OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process_id})")
75     end
76 
77     yield phandle
78   ensure
79     FFI::WIN32.CloseHandle(phandle) if phandle
80   end
81 
82   # phandle has had CloseHandle called against it, so nothing to return
83   nil
84 end
open_process_token(handle, desired_access) { |token_handle = read_handle| ... } click to toggle source
    # File lib/puppet/util/windows/process.rb
 87 def open_process_token(handle, desired_access, &block)
 88   token_handle = nil
 89   begin
 90     FFI::MemoryPointer.new(:handle, 1) do |token_handle_ptr|
 91       result = OpenProcessToken(handle, desired_access, token_handle_ptr)
 92       if result == FFI::WIN32_FALSE
 93         raise Puppet::Util::Windows::Error.new(
 94           "OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{token_handle_ptr})")
 95       end
 96 
 97       yield token_handle = token_handle_ptr.read_handle
 98     end
 99 
100     token_handle
101   ensure
102     FFI::WIN32.CloseHandle(token_handle) if token_handle
103   end
104 
105   # token_handle has had CloseHandle called against it, so nothing to return
106   nil
107 end
parse_token_information_as_token_elevation(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
217 def parse_token_information_as_token_elevation(token_information_buf)
218   TOKEN_ELEVATION.new(token_information_buf)
219 end
parse_token_information_as_token_privileges(token_information_buf) click to toggle source
    # File lib/puppet/util/windows/process.rb
201 def parse_token_information_as_token_privileges(token_information_buf)
202   raw_privileges = TOKEN_PRIVILEGES.new(token_information_buf)
203   privileges = { :count => raw_privileges[:PrivilegeCount], :privileges => [] }
204 
205   offset = token_information_buf + TOKEN_PRIVILEGES.offset_of(:Privileges)
206   privilege_ptr = FFI::Pointer.new(LUID_AND_ATTRIBUTES, offset)
207 
208   # extract each instance of LUID_AND_ATTRIBUTES
209   0.upto(privileges[:count] - 1) do |i|
210     privileges[:privileges] <<  LUID_AND_ATTRIBUTES.new(privilege_ptr[i])
211   end
212 
213   privileges
214 end
set_environment_variable(name, val) click to toggle source
    # File lib/puppet/util/windows/process.rb
330 def set_environment_variable(name, val)
331   raise Puppet::Util::Windows::Error(_('environment variable name must not be nil or empty')) if ! name || name.empty?
332 
333   FFI::MemoryPointer.from_string_to_wide_string(name) do |name_ptr|
334     if (val.nil?)
335       if SetEnvironmentVariableW(name_ptr, FFI::MemoryPointer::NULL) == FFI::WIN32_FALSE
336         raise Puppet::Util::Windows::Error.new(_("Failed to remove environment variable: %{name}") % { name: name })
337       end
338     else
339       FFI::MemoryPointer.from_string_to_wide_string(val) do |val_ptr|
340         if SetEnvironmentVariableW(name_ptr, val_ptr) == FFI::WIN32_FALSE
341           raise Puppet::Util::Windows::Error.new(_("Failed to set environment variable: %{name}") % { name: name })
342         end
343       end
344     end
345   end
346 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
359 def supports_elevated_security?
360   windows_major_version >= 6
361 end
wait_process(handle) click to toggle source
   # File lib/puppet/util/windows/process.rb
38 def wait_process(handle)
39   while WaitForSingleObject(handle, WAIT_INTERVAL) == WAIT_TIMEOUT
40     sleep(0)
41   end
42 
43   exit_status = -1
44   FFI::MemoryPointer.new(:dword, 1) do |exit_status_ptr|
45     if GetExitCodeProcess(handle, exit_status_ptr) == FFI::WIN32_FALSE
46       raise Puppet::Util::Windows::Error.new(_("Failed to get child process exit code"))
47     end
48     exit_status = exit_status_ptr.read_dword
49 
50     # $CHILD_STATUS is not set when calling win32/process Process.create
51     # and since it's read-only, we can't set it. But we can execute a
52     # a shell that simply returns the desired exit status, which has the
53     # desired effect.
54     %x{#{ENV['COMSPEC']} /c exit #{exit_status}}
55   end
56 
57   exit_status
58 end
windows_major_version() click to toggle source
    # File lib/puppet/util/windows/process.rb
276 def windows_major_version
277   ver = 0
278 
279   FFI::MemoryPointer.new(OSVERSIONINFO.size) do |os_version_ptr|
280     os_version = OSVERSIONINFO.new(os_version_ptr)
281     os_version[:dwOSVersionInfoSize] = OSVERSIONINFO.size
282 
283     result = GetVersionExW(os_version_ptr)
284 
285     if result == FFI::WIN32_FALSE
286       raise Puppet::Util::Windows::Error.new(_("GetVersionEx failed"))
287     end
288 
289     ver = os_version[:dwMajorVersion]
290   end
291 
292   ver
293 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
111 def with_process_token(access, &block)
112   handle = get_current_process
113   open_process_token(handle, access) do |token_handle|
114     yield token_handle
115   end
116 
117   # all handles have been closed, so nothing to safely return
118   nil
119 end