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
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
# 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
# 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
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
# 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
# File lib/puppet/util/windows/process.rb 349 def get_system_default_ui_language 350 GetSystemDefaultUILanguage() 351 end
# 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
# 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
# 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
# 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
# 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
# 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
# File lib/puppet/util/windows/process.rb 224 def process_privilege_symlink? 225 privilege_symlink = false 226 handle = get_current_process 227 open_process_token(handle, TOKEN_ALL_ACCESS) do |token_handle| 228 lookup_privilege_value('SeCreateSymbolicLinkPrivilege') do |luid| 229 get_token_information(token_handle, :TokenPrivileges) do |token_info| 230 token_privileges = parse_token_information_as_token_privileges(token_info) 231 privilege_symlink = token_privileges[:privileges].any? { |p| p[:Luid].values == luid.values } 232 end 233 end 234 end 235 236 privilege_symlink 237 rescue Puppet::Util::Windows::Error => e 238 if e.code == ERROR_NO_SUCH_PRIVILEGE 239 false # pre-Vista 240 else 241 raise e 242 end 243 end
# 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
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
# 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
# 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
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
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
# 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
# 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
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
# 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
# File lib/puppet/util/windows/process.rb 349 def get_system_default_ui_language 350 GetSystemDefaultUILanguage() 351 end
# 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
# 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
# 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
# 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
# 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
# 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
# File lib/puppet/util/windows/process.rb 224 def process_privilege_symlink? 225 privilege_symlink = false 226 handle = get_current_process 227 open_process_token(handle, TOKEN_ALL_ACCESS) do |token_handle| 228 lookup_privilege_value('SeCreateSymbolicLinkPrivilege') do |luid| 229 get_token_information(token_handle, :TokenPrivileges) do |token_info| 230 token_privileges = parse_token_information_as_token_privileges(token_info) 231 privilege_symlink = token_privileges[:privileges].any? { |p| p[:Luid].values == luid.values } 232 end 233 end 234 end 235 236 privilege_symlink 237 rescue Puppet::Util::Windows::Error => e 238 if e.code == ERROR_NO_SUCH_PRIVILEGE 239 false # pre-Vista 240 else 241 raise e 242 end 243 end
# 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
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
# 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
# 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
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