Class: WinRM::SOAP::WinRMWebService
- Inherits:
-
Handsoap::Service
- Object
- Handsoap::Service
- WinRM::SOAP::WinRMWebService
- Includes:
- WinRM::SOAP
- Defined in:
- lib/soap/winrm_service.rb
Constant Summary collapse
- @@raw_soap =
false
Constants included from WinRM::SOAP
NS_ADDRESSING, NS_CIMBINDING, NS_ENUM, NS_SCHEMA_INST, NS_TRANSFER, NS_WIN_SHELL, NS_WSMAN_DMTF, NS_WSMAN_MSFT
Class Method Summary collapse
-
.raw_soap! ⇒ Object
Turn off parsing and just return the soap response.
- .set_auth(user, pass) ⇒ Object
- .set_ca_trust_path(file_or_dir) ⇒ Object
Instance Method Summary collapse
-
#cleanup_command(shell_id, command_id) ⇒ true
Clean-up after a command.
-
#close_shell(shell_id) ⇒ true
Close the shell.
-
#get_command_output(shell_id, command_id) ⇒ Hash
Get the Output of the given shell and command.
-
#initialize ⇒ WinRMWebService
constructor
A new instance of WinRMWebService.
-
#iterate_hash_array(element, hash_array) ⇒ Object
To create an empty body set :soap_body => true in the invoke options and set the action to :nil_body.
- #on_after_create_http_request(req) ⇒ Object
-
#on_create_document(doc) ⇒ Object
********* Begin Hooks *********.
- #on_http_error(resp) ⇒ Object
-
#on_response_document(doc) ⇒ Object
Adds knowledge of namespaces to the response object.
-
#open_shell(i_stream = 'stdin', o_stream = 'stdout stderr') ⇒ String
Create a Shell on the destination host.
-
#run_cmd(command) ⇒ Hash
Run a CMD command.
-
#run_command(shell_id, command) ⇒ String
Run a command on a machine with an open shell.
-
#run_powershell_script(script_file) ⇒ Hash
Run a Powershell script that resides on the local box.
-
#run_wql(wql) ⇒ Array<Hash>
Run a WQL Query.
Constructor Details
#initialize ⇒ WinRMWebService
Returns a new instance of WinRMWebService.
29 30 31 32 33 34 |
# File 'lib/soap/winrm_service.rb', line 29 def initialize() if $DEBUG @debug = File.new('winrm_debug.out', 'w') @debug.sync = true end end |
Class Method Details
.raw_soap! ⇒ Object
Turn off parsing and just return the soap response
48 49 50 |
# File 'lib/soap/winrm_service.rb', line 48 def self.raw_soap! @@raw_soap = true end |
.set_auth(user, pass) ⇒ Object
36 37 38 39 40 |
# File 'lib/soap/winrm_service.rb', line 36 def self.set_auth(user,pass) @@user = user @@pass = pass true end |
.set_ca_trust_path(file_or_dir) ⇒ Object
42 43 44 45 |
# File 'lib/soap/winrm_service.rb', line 42 def self.set_ca_trust_path(file_or_dir) @@ca_trust_store = file_or_dir true end |
Instance Method Details
#cleanup_command(shell_id, command_id) ⇒ true
Clean-up after a command.
208 209 210 211 212 213 214 215 216 |
# File 'lib/soap/winrm_service.rb', line 208 def cleanup_command(shell_id, command_id) header = {}.merge(resource_uri_cmd).merge(action_signal).merge(selector_shell_id(shell_id)) # Signal the Command references to terminate (close stdout/stderr) resp = invoke("#{NS_WIN_SHELL}:Signal", {:soap_action => :auto, :http_options => nil, :soap_header => header}) do |sig| sig.set_attr('CommandId', command_id) sig.add("#{NS_WIN_SHELL}:Code",'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate') end true end |
#close_shell(shell_id) ⇒ true
Close the shell
221 222 223 224 225 226 |
# File 'lib/soap/winrm_service.rb', line 221 def close_shell(shell_id) header = {}.merge(resource_uri_cmd).merge(action_delete).merge(selector_shell_id(shell_id)) # Delete the Shell reference resp = invoke(:nil_body, {:soap_action => nil, :soap_body => true, :http_options => nil, :soap_header => header}) true end |
#get_command_output(shell_id, command_id) ⇒ Hash
Get the Output of the given shell and command
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/soap/winrm_service.rb', line 168 def get_command_output(shell_id, command_id) header = {}.merge(resource_uri_cmd).merge(action_receive).merge(selector_shell_id(shell_id)) # Get Command Output resp = invoke("#{NS_WIN_SHELL}:Receive", {:soap_action => :auto, :http_options => nil, :soap_header => header}) do |rec| rec.add("#{NS_WIN_SHELL}:DesiredStream",'stdout stderr') do |ds| ds.set_attr('CommandId', command_id) end end output = {:data => []} (resp/"//#{NS_WIN_SHELL}:Stream").each do |n| next if n.to_s.nil? output[:data] << {n['Name'].to_sym => Base64.decode64(n.to_s)} end # We may need to get additional output if the stream has not finished. # The CommandState will change from Running to Done like so: # @example # from... # <rsp:CommandState CommandId="495C3B09-E0B0-442A-9958-83B529F76C2C" State="http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Running"/> # to... # <rsp:CommandState CommandId="495C3B09-E0B0-442A-9958-83B529F76C2C" State="http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done"> # <rsp:ExitCode>0</rsp:ExitCode> # </rsp:CommandState> if((resp/"//#{NS_WIN_SHELL}:ExitCode").empty?) output.merge!(get_command_output(shell_id,command_id)) do |key, old_data, new_data| old_data += new_data end else output[:exitcode] = (resp/"//#{NS_WIN_SHELL}:ExitCode").first.to_i end output end |
#iterate_hash_array(element, hash_array) ⇒ Object
To create an empty body set :soap_body => true in the invoke options and set the action to :nil_body
297 298 299 |
# File 'lib/soap/winrm_service.rb', line 297 def iterate_hash_array(element, hash_array) add_hierarchy!(element, hash_array, nil) unless hash_array.key?(:nil_body) end |
#on_after_create_http_request(req) ⇒ Object
102 103 104 105 106 107 |
# File 'lib/soap/winrm_service.rb', line 102 def on_after_create_http_request(req) req.set_auth @@user, @@pass req.set_header('Content-Type','application/soap+xml;charset=UTF-8') req.set_trust_ca_file(@@ca_trust_store) if defined?(@@ca_trust_store) #puts "SOAP DOCUMENT=\n#{req.body}" end |
#on_create_document(doc) ⇒ Object
********* Begin Hooks *********
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/soap/winrm_service.rb', line 55 def on_create_document(doc) doc.alias NS_ADDRESSING, 'http://schemas.xmlsoap.org/ws/2004/08/addressing' doc.alias NS_ENUM, 'http://schemas.xmlsoap.org/ws/2004/09/enumeration' doc.alias NS_WSMAN_DMTF, 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' doc.alias NS_WSMAN_MSFT, 'http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd' doc.alias NS_SCHEMA_INST,'http://www.w3.org/2001/XMLSchema-instance' doc.alias NS_WIN_SHELL, 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell' doc.alias NS_CIMBINDING, 'http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd' header = doc.find('Header') header.add("#{NS_ADDRESSING}:To", WinRMWebService.uri) header.add("#{NS_ADDRESSING}:ReplyTo") {|rto| rto.add("#{NS_ADDRESSING}:Address",'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous') {|addr| addr.set_attr('mustUnderstand','true') } } header.add("#{NS_WSMAN_DMTF}:MaxEnvelopeSize",'153600') {|mes| mes.set_attr('mustUnderstand','true') } header.add("#{NS_ADDRESSING}:MessageID", "uuid:#{UUID.generate.upcase}") header.add("#{NS_WSMAN_DMTF}:Locale") {|loc| loc.set_attr('xml:lang','en-US') loc.set_attr('mustUnderstand','false') } header.add("#{NS_WSMAN_MSFT}:DataLocale") {|loc| loc.set_attr('xml:lang','en-US') loc.set_attr('mustUnderstand','false') } header.add("#{NS_WSMAN_DMTF}:OperationTimeout",'PT60.000S') end |
#on_http_error(resp) ⇒ Object
109 110 111 112 113 114 115 116 |
# File 'lib/soap/winrm_service.rb', line 109 def on_http_error(resp) case resp.status when 401 raise WinRMAuthorizationError, "#{resp.headers}\n------\n#{resp.body}" else raise WinRMWebServiceError, "#{resp.headers}\n------\n#{resp.body}" end end |
#on_response_document(doc) ⇒ Object
Adds knowledge of namespaces to the response object. These have to be identical to the URIs returned in the XML response. For example, I had some issues with the ‘soap’ namespace because my original URI did not end in a ‘/’
92 93 94 95 96 97 98 99 100 |
# File 'lib/soap/winrm_service.rb', line 92 def on_response_document(doc) doc.add_namespace NS_ADDRESSING, 'http://schemas.xmlsoap.org/ws/2004/08/addressing' doc.add_namespace NS_ENUM, 'http://schemas.xmlsoap.org/ws/2004/09/enumeration' doc.add_namespace NS_TRANSFER, 'http://schemas.xmlsoap.org/ws/2004/09/transfer' doc.add_namespace NS_WSMAN_DMTF, 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' doc.add_namespace NS_WSMAN_MSFT, 'http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd' doc.add_namespace NS_WIN_SHELL, 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell' doc.add_namespace NS_CIMBINDING, 'http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd' end |
#open_shell(i_stream = 'stdin', o_stream = 'stdout stderr') ⇒ String
Create a Shell on the destination host
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/soap/winrm_service.rb', line 126 def open_shell(i_stream = 'stdin', o_stream = 'stdout stderr') header = { "#{NS_WSMAN_DMTF}:OptionSet" => [ {"#{NS_WSMAN_DMTF}:Option" => {:name => 'WINRS_NOPROFILE', :text =>"FALSE"}}, {"#{NS_WSMAN_DMTF}:Option" => {:name => 'WINRS_CODEPAGE', :text =>"437"}} ] }.merge(resource_uri_cmd).merge(action_create) resp = invoke("#{NS_WIN_SHELL}:Shell", {:soap_action => :auto, :http_options => nil, :soap_header => header}) do |shell| shell.add("#{NS_WIN_SHELL}:InputStreams", i_stream) shell.add("#{NS_WIN_SHELL}:OutputStreams",o_stream) end # Get the Shell ID from the response (resp/"//*[@Name='ShellId']").to_s end |
#run_cmd(command) ⇒ Hash
Run a CMD command
231 232 233 234 235 236 237 238 |
# File 'lib/soap/winrm_service.rb', line 231 def run_cmd(command) shell_id = open_shell command_id = run_command(shell_id, command) command_output = get_command_output(shell_id, command_id) cleanup_command(shell_id, command_id) close_shell(shell_id) command_output end |
#run_command(shell_id, command) ⇒ String
Run a command on a machine with an open shell
147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/soap/winrm_service.rb', line 147 def run_command(shell_id, command) header = { "#{NS_WSMAN_DMTF}:OptionSet" => { "#{NS_WSMAN_DMTF}:Option" => {:name => 'WINRS_CONSOLEMODE_STDIN', :text =>"TRUE"}, } }.merge(resource_uri_cmd).merge(action_command).merge(selector_shell_id(shell_id)) # Issue the Command resp = invoke("#{NS_WIN_SHELL}:CommandLine", {:soap_action => :auto, :http_options => nil, :soap_header => header}) do |cli| cli.add("#{NS_WIN_SHELL}:Command","\"#{command}\"") end (resp/"//#{NS_WIN_SHELL}:CommandId").to_s end |
#run_powershell_script(script_file) ⇒ Hash
Run a Powershell script that resides on the local box.
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/soap/winrm_service.rb', line 244 def run_powershell_script(script_file) script = File.read(script_file) script = script.chars.to_a.join("\x00").chomp if(defined?(script.encode)) script = script.encode('ASCII-8BIT') script = Base64.strict_encode64(script) else script = Base64.encode64(script).chomp end shell_id = open_shell command_id = run_command(shell_id, "powershell -encodedCommand #{script}") command_output = get_command_output(shell_id, command_id) cleanup_command(shell_id, command_id) close_shell(shell_id) command_output end |
#run_wql(wql) ⇒ Array<Hash>
Run a WQL Query
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/soap/winrm_service.rb', line 268 def run_wql(wql) header = {}.merge(resource_uri_wmi).merge(action_enumerate) begin resp = invoke("#{NS_ENUM}:Enumerate", {:soap_action => :auto, :http_options => nil, :soap_header => header}) do |enum| enum.add("#{NS_WSMAN_DMTF}:OptimizeEnumeration") enum.add("#{NS_WSMAN_DMTF}:MaxElements",'32000') mattr = nil enum.add("#{NS_WSMAN_DMTF}:Filter", wql) do |filt| filt.set_attr('Dialect','http://schemas.microsoft.com/wbem/wsman/1/WQL') end end rescue Handsoap::Fault => e raise WinRMWebServiceError, e.reason end query_response = [] (resp/"//#{NS_ENUM}:EnumerateResponse//#{NS_WSMAN_DMTF}:Items/*").each do |i| qitem = {} (i/'*').each do |si| qitem[si.node_name] = si.to_s end query_response << qitem end query_response end |