chef-winrm 2.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +202 -0
  3. data/README.md +277 -0
  4. data/bin/rwinrm +90 -0
  5. data/lib/winrm/connection.rb +84 -0
  6. data/lib/winrm/connection_opts.rb +92 -0
  7. data/lib/winrm/exceptions.rb +88 -0
  8. data/lib/winrm/http/response_handler.rb +127 -0
  9. data/lib/winrm/http/transport.rb +466 -0
  10. data/lib/winrm/http/transport_factory.rb +64 -0
  11. data/lib/winrm/output.rb +58 -0
  12. data/lib/winrm/psrp/create_pipeline.xml.erb +167 -0
  13. data/lib/winrm/psrp/fragment.rb +68 -0
  14. data/lib/winrm/psrp/init_runspace_pool.xml.erb +224 -0
  15. data/lib/winrm/psrp/message.rb +128 -0
  16. data/lib/winrm/psrp/message_data/base.rb +47 -0
  17. data/lib/winrm/psrp/message_data/error_record.rb +68 -0
  18. data/lib/winrm/psrp/message_data/pipeline_host_call.rb +30 -0
  19. data/lib/winrm/psrp/message_data/pipeline_output.rb +48 -0
  20. data/lib/winrm/psrp/message_data/pipeline_state.rb +38 -0
  21. data/lib/winrm/psrp/message_data/runspacepool_host_call.rb +30 -0
  22. data/lib/winrm/psrp/message_data/runspacepool_state.rb +37 -0
  23. data/lib/winrm/psrp/message_data/session_capability.rb +34 -0
  24. data/lib/winrm/psrp/message_data.rb +40 -0
  25. data/lib/winrm/psrp/message_defragmenter.rb +62 -0
  26. data/lib/winrm/psrp/message_factory.rb +86 -0
  27. data/lib/winrm/psrp/message_fragmenter.rb +58 -0
  28. data/lib/winrm/psrp/powershell_output_decoder.rb +142 -0
  29. data/lib/winrm/psrp/receive_response_reader.rb +95 -0
  30. data/lib/winrm/psrp/session_capability.xml.erb +7 -0
  31. data/lib/winrm/psrp/uuid.rb +39 -0
  32. data/lib/winrm/shells/base.rb +192 -0
  33. data/lib/winrm/shells/cmd.rb +59 -0
  34. data/lib/winrm/shells/power_shell.rb +202 -0
  35. data/lib/winrm/shells/retryable.rb +44 -0
  36. data/lib/winrm/shells/shell_factory.rb +56 -0
  37. data/lib/winrm/version.rb +5 -0
  38. data/lib/winrm/wsmv/base.rb +57 -0
  39. data/lib/winrm/wsmv/cleanup_command.rb +60 -0
  40. data/lib/winrm/wsmv/close_shell.rb +49 -0
  41. data/lib/winrm/wsmv/command.rb +100 -0
  42. data/lib/winrm/wsmv/command_output.rb +75 -0
  43. data/lib/winrm/wsmv/command_output_decoder.rb +54 -0
  44. data/lib/winrm/wsmv/configuration.rb +44 -0
  45. data/lib/winrm/wsmv/create_pipeline.rb +64 -0
  46. data/lib/winrm/wsmv/create_shell.rb +115 -0
  47. data/lib/winrm/wsmv/header.rb +213 -0
  48. data/lib/winrm/wsmv/init_runspace_pool.rb +96 -0
  49. data/lib/winrm/wsmv/iso8601_duration.rb +58 -0
  50. data/lib/winrm/wsmv/keep_alive.rb +66 -0
  51. data/lib/winrm/wsmv/receive_response_reader.rb +128 -0
  52. data/lib/winrm/wsmv/send_data.rb +66 -0
  53. data/lib/winrm/wsmv/soap.rb +49 -0
  54. data/lib/winrm/wsmv/wql_pull.rb +54 -0
  55. data/lib/winrm/wsmv/wql_query.rb +98 -0
  56. data/lib/winrm/wsmv/write_stdin.rb +86 -0
  57. data/lib/winrm.rb +37 -0
  58. metadata +333 -0
@@ -0,0 +1,56 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+ require_relative 'cmd'
17
+ require_relative 'power_shell'
18
+
19
+ module WinRM
20
+ module Shells
21
+ # Factory for creating concrete shell instances
22
+ class ShellFactory
23
+ # Creates a new ShellFactory instance
24
+ # @param connection_opts [ConnectionOpts] The WinRM connection options
25
+ # @param transport [HttpTransport] The WinRM SOAP transport for sending messages
26
+ # @param logger [Logger] The logger to log messages to
27
+ def initialize(connection_opts, transport, logger)
28
+ @connection_opts = connection_opts
29
+ @transport = transport
30
+ @logger = logger
31
+ end
32
+
33
+ # Creates a new shell instance based off the shell_type
34
+ # @param shell_type [Symbol] The shell type :cmd or :powershell
35
+ # @param shell_opts [Hash] Options targeted for the created shell
36
+ # @return The ready to use shell instance
37
+ def create_shell(shell_type, shell_opts = {})
38
+ type = shell_type.to_s.capitalize.to_sym
39
+ args = [
40
+ @connection_opts,
41
+ @transport,
42
+ @logger
43
+ ]
44
+ # winrm-elevated has an initializer with no shell_opts so don't break it
45
+ args << shell_opts unless shell_opts.nil? || shell_opts.empty?
46
+ if Shells.constants.include?(type)
47
+ WinRM::Shells.const_get(type).new(*args)
48
+ else
49
+ message = "#{type} is not a valid WinRM shell type. " \
50
+ 'Expected either :cmd, :powershell or pluggable shell.'
51
+ raise WinRM::InvalidShellError, message
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ # WinRM module
2
+ module WinRM
3
+ # The version of the WinRM library
4
+ VERSION = '2.3.10'.freeze
5
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'base64'
16
+ require 'builder'
17
+ require 'gyoku'
18
+ require_relative 'soap'
19
+ require_relative 'header'
20
+
21
+ module WinRM
22
+ module WSMV
23
+ # Base class for all WSMV message classes
24
+ class Base
25
+ include WinRM::WSMV::SOAP
26
+ include WinRM::WSMV::Header
27
+
28
+ # Builds the WSMV message XML payload
29
+ def build
30
+ builder = Builder::XmlMarkup.new
31
+ builder.instruct!(:xml, encoding: 'UTF-8')
32
+ builder.tag! :env, :Envelope, namespaces do |env|
33
+ env.tag!(:env, :Header) do |env_header|
34
+ create_header(env_header)
35
+ end
36
+ env.tag!(:env, :Body) do |env_body|
37
+ create_body(env_body)
38
+ end
39
+ end
40
+ end
41
+
42
+ protected
43
+
44
+ def create_header
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def create_body
49
+ raise NotImplementedError
50
+ end
51
+
52
+ def encode_bytes(bytes)
53
+ Base64.strict_encode64(bytes.pack('C*'))
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,60 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+
17
+ module WinRM
18
+ module WSMV
19
+ # WSMV message to execute a command inside a remote shell
20
+ class CleanupCommand < Base
21
+ def initialize(session_opts, opts)
22
+ raise 'opts[:shell_id] is required' unless opts[:shell_id]
23
+ raise 'opts[:command_id] is required' unless opts[:command_id]
24
+
25
+ @session_opts = session_opts
26
+ @shell_id = opts[:shell_id]
27
+ @command_id = opts[:command_id]
28
+ @shell_uri = opts[:shell_uri] || RESOURCE_URI_CMD
29
+ end
30
+
31
+ protected
32
+
33
+ def create_header(header)
34
+ header << Gyoku.xml(cleanup_header)
35
+ end
36
+
37
+ def create_body(body)
38
+ body.tag!("#{NS_WIN_SHELL}:Signal", 'CommandId' => @command_id) do |cl|
39
+ cl << Gyoku.xml(cleanup_body)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def cleanup_header
46
+ merge_headers(shared_headers(@session_opts),
47
+ resource_uri_shell(@shell_uri),
48
+ action_signal,
49
+ selector_shell_id(@shell_id))
50
+ end
51
+
52
+ def cleanup_body
53
+ {
54
+ "#{NS_WIN_SHELL}:Code" =>
55
+ 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate'
56
+ }
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+
17
+ module WinRM
18
+ module WSMV
19
+ # WSMV message to close a remote shell
20
+ class CloseShell < Base
21
+ def initialize(session_opts, shell_opts)
22
+ raise 'shell_opts[:shell_id] is required' unless shell_opts[:shell_id]
23
+
24
+ @session_opts = session_opts
25
+ @shell_id = shell_opts[:shell_id]
26
+ @shell_uri = shell_opts[:shell_uri] || RESOURCE_URI_CMD
27
+ end
28
+
29
+ protected
30
+
31
+ def create_header(header)
32
+ header << Gyoku.xml(close_header)
33
+ end
34
+
35
+ def create_body(_body)
36
+ # no body
37
+ end
38
+
39
+ private
40
+
41
+ def close_header
42
+ merge_headers(shared_headers(@session_opts),
43
+ resource_uri_shell(@shell_uri),
44
+ action_delete,
45
+ selector_shell_id(@shell_id))
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,100 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+
17
+ module WinRM
18
+ module WSMV
19
+ # WSMV message to execute a command inside a remote shell
20
+ class Command < Base
21
+ attr_reader :command_id
22
+
23
+ def initialize(session_opts, cmd_opts)
24
+ @command_id = SecureRandom.uuid.to_s.upcase
25
+ validate_opts(session_opts, cmd_opts)
26
+ init_ops(session_opts, cmd_opts)
27
+ end
28
+
29
+ def build
30
+ xml = super
31
+ issue69_unescape_single_quotes(xml)
32
+ end
33
+
34
+ protected
35
+
36
+ def create_header(header)
37
+ header << Gyoku.xml(command_headers)
38
+ end
39
+
40
+ def create_body(body)
41
+ body.tag!("#{NS_WIN_SHELL}:CommandLine", 'CommandId' => @command_id) do |cl|
42
+ cl << Gyoku.xml(command_body)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def init_ops(session_opts, cmd_opts)
49
+ @session_opts = session_opts
50
+ @shell_id = cmd_opts[:shell_id]
51
+ @command = cmd_opts[:command]
52
+ @arguments = cmd_opts[:arguments] || []
53
+ @shell_uri = cmd_opts[:shell_uri] || RESOURCE_URI_CMD
54
+ @consolemode = cmd_opts.key?(:console_mode_stdin) ? cmd_opts[:console_mode_stdin] : 'TRUE'
55
+ @skipcmd = cmd_opts.key?(:skip_cmd_shell) ? cmd_opts[:skip_cmd_shell] : 'FALSE'
56
+ end
57
+
58
+ def validate_opts(session_opts, cmd_opts)
59
+ raise 'session_opts is required' unless session_opts
60
+ raise 'cmd_opts[:shell_id] is required' unless cmd_opts[:shell_id]
61
+ raise 'cmd_opts[:command] is required' unless cmd_opts[:command]
62
+ end
63
+
64
+ def issue69_unescape_single_quotes(xml)
65
+ escaped_cmd = %r{<#{NS_WIN_SHELL}:Command>(.+)<\/#{NS_WIN_SHELL}:Command>}m.match(xml)[1]
66
+ xml[escaped_cmd] = escaped_cmd.gsub(/&#39;/, "'")
67
+ xml
68
+ end
69
+
70
+ def command_body
71
+ {
72
+ "#{NS_WIN_SHELL}:Command" => "\"#{@command}\"", "#{NS_WIN_SHELL}:Arguments" => @arguments
73
+ }
74
+ end
75
+
76
+ def command_headers
77
+ merge_headers(shared_headers(@session_opts),
78
+ resource_uri_shell(@shell_uri),
79
+ action_command,
80
+ command_header_opts,
81
+ selector_shell_id(@shell_id))
82
+ end
83
+
84
+ def command_header_opts
85
+ return {} if @shell_uri != RESOURCE_URI_CMD
86
+
87
+ # this is only needed for the regular Windows shell
88
+ {
89
+ "#{NS_WSMAN_DMTF}:OptionSet" => {
90
+ "#{NS_WSMAN_DMTF}:Option" => [@consolemode, @skipcmd], :attributes! => {
91
+ "#{NS_WSMAN_DMTF}:Option" => {
92
+ 'Name' => %w[WINRS_CONSOLEMODE_STDIN WINRS_SKIP_CMD_SHELL]
93
+ }
94
+ }
95
+ }
96
+ }
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,75 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+
17
+ module WinRM
18
+ module WSMV
19
+ # WSMV message to get output from a remote shell
20
+ class CommandOutput < Base
21
+ def initialize(session_opts, command_out_opts)
22
+ raise 'command_out_opts[:shell_id] is required' unless command_out_opts[:shell_id]
23
+ raise 'command_out_opts[:command_id] is required' unless command_out_opts[:command_id]
24
+
25
+ @session_opts = session_opts
26
+ @shell_id = command_out_opts[:shell_id]
27
+ @command_id = command_out_opts[:command_id]
28
+ @shell_uri = command_out_opts[:shell_uri] || RESOURCE_URI_CMD
29
+ @out_streams = command_out_opts[:out_streams] || %w[stdout stderr]
30
+ end
31
+
32
+ protected
33
+
34
+ def create_header(header)
35
+ header << Gyoku.xml(output_header)
36
+ end
37
+
38
+ def create_body(body)
39
+ body.tag!("#{NS_WIN_SHELL}:Receive") { |cl| cl << Gyoku.xml(output_body) }
40
+ end
41
+
42
+ private
43
+
44
+ def output_header
45
+ merge_headers(shared_headers(@session_opts),
46
+ resource_uri_shell(@shell_uri),
47
+ action_receive,
48
+ header_opts,
49
+ selector_shell_id(@shell_id))
50
+ end
51
+
52
+ def header_opts
53
+ {
54
+ "#{NS_WSMAN_DMTF}:OptionSet" => {
55
+ "#{NS_WSMAN_DMTF}:Option" => 'TRUE', :attributes! => {
56
+ "#{NS_WSMAN_DMTF}:Option" => {
57
+ 'Name' => 'WSMAN_CMDSHELL_OPTION_KEEPALIVE'
58
+ }
59
+ }
60
+ }
61
+ }
62
+ end
63
+
64
+ def output_body
65
+ {
66
+ "#{NS_WIN_SHELL}:DesiredStream" => @out_streams.join(' '), :attributes! => {
67
+ "#{NS_WIN_SHELL}:DesiredStream" => {
68
+ 'CommandId' => @command_id
69
+ }
70
+ }
71
+ }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'base64'
16
+
17
+ module WinRM
18
+ module WSMV
19
+ # Handles decoding a raw output response
20
+ class CommandOutputDecoder
21
+ # Decode the raw SOAP output into decoded and human consumable text,
22
+ # Decodes and replaces invalid unicode characters.
23
+ # @param raw_output [String] The raw encoded output
24
+ # @return [String] The decoded output
25
+ def decode(raw_output)
26
+ decoded_text = decode_raw_output(raw_output)
27
+ decoded_text = handle_invalid_encoding(decoded_text)
28
+ decoded_text = remove_bom(decoded_text)
29
+ decoded_text
30
+ end
31
+
32
+ private
33
+
34
+ def decode_raw_output(raw_output)
35
+ Base64.decode64(raw_output).force_encoding('utf-8')
36
+ end
37
+
38
+ def handle_invalid_encoding(decoded_text)
39
+ return decoded_text if decoded_text.valid_encoding?
40
+
41
+ if decoded_text.respond_to?(:scrub)
42
+ decoded_text.scrub
43
+ else
44
+ decoded_text.encode('utf-16', invalid: :replace, undef: :replace).encode('utf-8')
45
+ end
46
+ end
47
+
48
+ def remove_bom(decoded_text)
49
+ # remove BOM which 2008R2 applies
50
+ decoded_text.sub("\xEF\xBB\xBF", '')
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,44 @@
1
+ # Copyright 2016 Matt Wrock <matt@mattwrock.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+
17
+ module WinRM
18
+ module WSMV
19
+ # WSMV keep alive message
20
+ class Configuration < Base
21
+ def initialize(session_opts)
22
+ @session_opts = session_opts
23
+ end
24
+
25
+ protected
26
+
27
+ def create_header(header)
28
+ header << Gyoku.xml(configuration_headers)
29
+ end
30
+
31
+ def create_body(_body)
32
+ # no body
33
+ end
34
+
35
+ private
36
+
37
+ def configuration_headers
38
+ merge_headers(shared_headers(@session_opts),
39
+ resource_uri_shell('http://schemas.microsoft.com/wbem/wsman/1/config'),
40
+ action_get)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,64 @@
1
+ # Copyright 2016 Matt Wrock <matt@mattwrock.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+ require_relative '../psrp/message_factory'
17
+
18
+ module WinRM
19
+ module WSMV
20
+ # WSMV message to execute a command via psrp
21
+ class CreatePipeline < Base
22
+ attr_accessor :shell_id, :command_id, :fragment
23
+
24
+ def initialize(session_opts, shell_id, command_id, fragment = nil)
25
+ @command_id = command_id
26
+ @session_opts = session_opts
27
+ @shell_id = shell_id
28
+ @fragment = fragment
29
+ end
30
+
31
+ protected
32
+
33
+ def create_header(header)
34
+ header << Gyoku.xml(command_headers)
35
+ end
36
+
37
+ def create_body(body)
38
+ body.tag!("#{NS_WIN_SHELL}:CommandLine", 'CommandId' => command_id) do |cl|
39
+ cl << Gyoku.xml(command_body)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def command_body
46
+ {
47
+ "#{NS_WIN_SHELL}:Command" => 'Invoke-Expression',
48
+ "#{NS_WIN_SHELL}:Arguments" => arguments
49
+ }
50
+ end
51
+
52
+ def command_headers
53
+ merge_headers(shared_headers(@session_opts),
54
+ resource_uri_shell(RESOURCE_URI_POWERSHELL),
55
+ action_command,
56
+ selector_shell_id(shell_id))
57
+ end
58
+
59
+ def arguments
60
+ encode_bytes(fragment.bytes) if fragment
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,115 @@
1
+ # Copyright 2016 Shawn Neal <sneal@sneal.net>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'base'
16
+ require_relative 'iso8601_duration'
17
+
18
+ module WinRM
19
+ module WSMV
20
+ # WSMV message to create a remote shell
21
+ class CreateShell < Base
22
+ # utf8 as default codepage
23
+ # https://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
24
+ UTF8_CODE_PAGE = 65001
25
+
26
+ attr_accessor :i_stream, :o_stream, :codepage, :noprofile
27
+ attr_accessor :working_directory, :idle_timeout, :env_vars
28
+
29
+ def initialize(session_opts, shell_opts = {})
30
+ @session_opts = session_opts
31
+ @shell_uri = opt_or_default(shell_opts, :shell_uri, RESOURCE_URI_CMD)
32
+ @i_stream = opt_or_default(shell_opts, :i_stream, 'stdin')
33
+ @o_stream = opt_or_default(shell_opts, :o_stream, 'stdout stderr')
34
+ @codepage = opt_or_default(shell_opts, :codepage, UTF8_CODE_PAGE)
35
+ @noprofile = opt_or_default(shell_opts, :noprofile, 'FALSE')
36
+ @working_directory = opt_or_default(shell_opts, :working_directory)
37
+ @idle_timeout = opt_or_default(shell_opts, :idle_timeout)
38
+ @env_vars = opt_or_default(shell_opts, :env_vars)
39
+ end
40
+
41
+ protected
42
+
43
+ def create_header(header)
44
+ header << Gyoku.xml(shell_headers)
45
+ end
46
+
47
+ def create_body(body)
48
+ body.tag!("#{NS_WIN_SHELL}:Shell") { |s| s << Gyoku.xml(shell_body) }
49
+ end
50
+
51
+ private
52
+
53
+ def opt_or_default(shell_opts, key, default_value = nil)
54
+ shell_opts.key?(key) ? shell_opts[key] : default_value
55
+ end
56
+
57
+ def shell_body
58
+ body = {
59
+ "#{NS_WIN_SHELL}:InputStreams" => @i_stream,
60
+ "#{NS_WIN_SHELL}:OutputStreams" => @o_stream
61
+ }
62
+ body["#{NS_WIN_SHELL}:WorkingDirectory"] = @working_directory if @working_directory
63
+ body["#{NS_WIN_SHELL}:IdleTimeOut"] = format_idle_timeout(@idle_timeout) if @idle_timeout
64
+ body["#{NS_WIN_SHELL}:Environment"] = environment_vars_body if @env_vars
65
+ body
66
+ end
67
+
68
+ # backwards compat - idle_timeout as an Iso8601Duration string
69
+ def format_idle_timeout(timeout)
70
+ timeout.is_a?(String) ? timeout : Iso8601Duration.sec_to_dur(timeout)
71
+ end
72
+
73
+ def environment_vars_body
74
+ {
75
+ "#{NS_WIN_SHELL}:Variable" => @env_vars.values,
76
+ :attributes! => {
77
+ "#{NS_WIN_SHELL}:Variable" => {
78
+ 'Name' => @env_vars.keys
79
+ }
80
+ }
81
+ }
82
+ end
83
+
84
+ def shell_headers
85
+ merge_headers(shared_headers(@session_opts),
86
+ resource_uri_shell(@shell_uri),
87
+ action_create,
88
+ header_opts)
89
+ end
90
+
91
+ def action_create
92
+ {
93
+ "#{NS_ADDRESSING}:Action" => 'http://schemas.xmlsoap.org/ws/2004/09/transfer/Create',
94
+ :attributes! => {
95
+ "#{NS_ADDRESSING}:Action" => {
96
+ 'mustUnderstand' => true
97
+ }
98
+ }
99
+ }
100
+ end
101
+
102
+ def header_opts
103
+ {
104
+ "#{NS_WSMAN_DMTF}:OptionSet" => {
105
+ "#{NS_WSMAN_DMTF}:Option" => [@noprofile, @codepage], :attributes! => {
106
+ "#{NS_WSMAN_DMTF}:Option" => {
107
+ 'Name' => %w[WINRS_NOPROFILE WINRS_CODEPAGE]
108
+ }
109
+ }
110
+ }
111
+ }
112
+ end
113
+ end
114
+ end
115
+ end