knife-windows 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -5
  3. data/.travis.yml +20 -20
  4. data/CHANGELOG.md +87 -83
  5. data/DOC_CHANGES.md +20 -20
  6. data/Gemfile +12 -12
  7. data/LICENSE +201 -201
  8. data/README.md +396 -396
  9. data/RELEASE_NOTES.md +34 -34
  10. data/Rakefile +21 -21
  11. data/appveyor.yml +42 -42
  12. data/ci.gemfile +15 -15
  13. data/features/knife_help.feature +20 -20
  14. data/features/support/env.rb +5 -5
  15. data/knife-windows.gemspec +28 -28
  16. data/lib/chef/knife/bootstrap/windows-chef-client-msi.erb +247 -247
  17. data/lib/chef/knife/bootstrap_windows_base.rb +407 -401
  18. data/lib/chef/knife/bootstrap_windows_ssh.rb +110 -110
  19. data/lib/chef/knife/bootstrap_windows_winrm.rb +95 -102
  20. data/lib/chef/knife/core/windows_bootstrap_context.rb +362 -362
  21. data/lib/chef/knife/knife_windows_base.rb +33 -33
  22. data/lib/chef/knife/windows_cert_generate.rb +155 -155
  23. data/lib/chef/knife/windows_cert_install.rb +68 -68
  24. data/lib/chef/knife/windows_helper.rb +36 -36
  25. data/lib/chef/knife/windows_listener_create.rb +107 -107
  26. data/lib/chef/knife/winrm.rb +122 -212
  27. data/lib/chef/knife/winrm_base.rb +118 -118
  28. data/lib/chef/knife/winrm_knife_base.rb +309 -218
  29. data/lib/chef/knife/winrm_session.rb +82 -82
  30. data/lib/chef/knife/winrm_shared_options.rb +47 -47
  31. data/lib/chef/knife/wsman_endpoint.rb +44 -44
  32. data/lib/chef/knife/wsman_test.rb +95 -95
  33. data/lib/knife-windows/path_helper.rb +234 -234
  34. data/lib/knife-windows/version.rb +6 -6
  35. data/spec/assets/win_template_rendered_with_bootstrap_install_command.txt +217 -217
  36. data/spec/assets/win_template_rendered_with_bootstrap_install_command_on_12_5_client.txt +217 -217
  37. data/spec/assets/win_template_rendered_without_bootstrap_install_command.txt +329 -329
  38. data/spec/assets/win_template_rendered_without_bootstrap_install_command_on_12_5_client.txt +329 -329
  39. data/spec/assets/win_template_unrendered.txt +246 -246
  40. data/spec/functional/bootstrap_download_spec.rb +234 -233
  41. data/spec/spec_helper.rb +88 -88
  42. data/spec/unit/knife/bootstrap_options_spec.rb +148 -146
  43. data/spec/unit/knife/bootstrap_template_spec.rb +92 -92
  44. data/spec/unit/knife/bootstrap_windows_winrm_spec.rb +259 -243
  45. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +151 -151
  46. data/spec/unit/knife/windows_cert_generate_spec.rb +90 -90
  47. data/spec/unit/knife/windows_cert_install_spec.rb +51 -51
  48. data/spec/unit/knife/windows_listener_create_spec.rb +76 -76
  49. data/spec/unit/knife/winrm_session_spec.rb +73 -73
  50. data/spec/unit/knife/winrm_spec.rb +551 -504
  51. data/spec/unit/knife/wsman_test_spec.rb +178 -175
  52. metadata +3 -23
@@ -1,36 +1,36 @@
1
- #
2
- # Author:: Chirag Jog (<chirag@clogeny.com>)
3
- # Copyright:: Copyright (c) 2013 Opscode, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- require 'chef/knife'
20
- require 'chef/knife/winrm'
21
- require 'chef/knife/bootstrap_windows_ssh'
22
- require 'chef/knife/bootstrap_windows_winrm'
23
- require 'chef/knife/wsman_test'
24
-
25
- class Chef
26
- class Knife
27
- class WindowsHelper < Knife
28
-
29
- banner "#{BootstrapWindowsWinrm.banner}\n" +
30
- "#{BootstrapWindowsSsh.banner}\n" +
31
- "#{Winrm.banner}\n" +
32
- "#{WsmanTest.banner}"
33
- end
34
- end
35
- end
36
-
1
+ #
2
+ # Author:: Chirag Jog (<chirag@clogeny.com>)
3
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife'
20
+ require 'chef/knife/winrm'
21
+ require 'chef/knife/bootstrap_windows_ssh'
22
+ require 'chef/knife/bootstrap_windows_winrm'
23
+ require 'chef/knife/wsman_test'
24
+
25
+ class Chef
26
+ class Knife
27
+ class WindowsHelper < Knife
28
+
29
+ banner "#{BootstrapWindowsWinrm.banner}\n" +
30
+ "#{BootstrapWindowsSsh.banner}\n" +
31
+ "#{Winrm.banner}\n" +
32
+ "#{WsmanTest.banner}"
33
+ end
34
+ end
35
+ end
36
+
@@ -1,107 +1,107 @@
1
- # Author:: Mukta Aphale (<mukta.aphale@clogeny.com>)
2
- # Copyright:: Copyright (c) 2014 Opscode, Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require 'chef/knife'
19
- require 'chef/knife/winrm_base'
20
- require 'openssl'
21
-
22
- class Chef
23
- class Knife
24
- class WindowsListenerCreate < Knife
25
-
26
- banner "knife windows listener create (options)"
27
-
28
- option :cert_install,
29
- :short => "-c CERT_PATH",
30
- :long => "--cert-install CERT_PATH",
31
- :description => "Adds specified certificate to the Windows Certificate Store's Local Machine personal store before creating listener."
32
-
33
- option :port,
34
- :short => "-p PORT",
35
- :long => "--port PORT",
36
- :description => "Specify port. Default is 5986",
37
- :default => "5986"
38
-
39
- option :hostname,
40
- :short => "-h HOSTNAME",
41
- :long => "--hostname HOSTNAME",
42
- :description => "Hostname on the listener. Default is blank",
43
- :default => ""
44
-
45
- option :cert_thumbprint,
46
- :short => "-t THUMBPRINT",
47
- :long => "--cert-thumbprint THUMBPRINT",
48
- :description => "Thumbprint of the certificate. Required only if --cert-install option is not used."
49
-
50
- option :cert_passphrase,
51
- :short => "-cp PASSWORD",
52
- :long => "--cert-passphrase PASSWORD",
53
- :description => "Password for certificate."
54
-
55
- def get_cert_passphrase
56
- print "Enter given certificate's passphrase (empty for no passphrase):"
57
- passphrase = STDIN.gets
58
- passphrase.strip
59
- end
60
-
61
- def run
62
- STDOUT.sync = STDERR.sync = true
63
-
64
- if Chef::Platform.windows?
65
- begin
66
- if config[:cert_install]
67
- config[:cert_passphrase] = get_cert_passphrase unless config[:cert_passphrase]
68
- result = %x{powershell.exe -Command " '#{config[:cert_passphrase]}' | certutil -importPFX '#{config[:cert_install]}' AT_KEYEXCHANGE"}
69
- if $?.exitstatus
70
- ui.info "Certificate installed to Certificate Store"
71
- result = %x{powershell.exe -Command " echo (Get-PfxCertificate #{config[:cert_install]}).thumbprint "}
72
- ui.info "Certificate Thumbprint: #{result}"
73
- config[:cert_thumbprint] = result.strip
74
- else
75
- ui.error "Error installing certificate to Certificate Store"
76
- ui.error result
77
- exit 1
78
- end
79
- end
80
-
81
- unless config[:cert_thumbprint]
82
- ui.error "Please specify the --cert-thumbprint"
83
- exit 1
84
- end
85
-
86
- result = %x{winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="#{config[:hostname]}";CertificateThumbprint="#{config[:cert_thumbprint]}";Port="#{config[:port]}"}}
87
- Chef::Log.debug result
88
-
89
- if ($?.exitstatus == 0)
90
- ui.info "WinRM listener created with Port: #{config[:port]} and CertificateThumbprint: #{config[:cert_thumbprint]}"
91
- else
92
- ui.error "Error creating WinRM listener. use -VV for more details."
93
- exit 1
94
- end
95
-
96
- rescue => e
97
- puts "ERROR: + #{e}"
98
- end
99
- else
100
- ui.error "WinRM listener can be created on Windows system only"
101
- exit 1
102
- end
103
- end
104
-
105
- end
106
- end
107
- end
1
+ # Author:: Mukta Aphale (<mukta.aphale@clogeny.com>)
2
+ # Copyright:: Copyright (c) 2014 Opscode, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife'
19
+ require 'chef/knife/winrm_base'
20
+ require 'openssl'
21
+
22
+ class Chef
23
+ class Knife
24
+ class WindowsListenerCreate < Knife
25
+
26
+ banner "knife windows listener create (options)"
27
+
28
+ option :cert_install,
29
+ :short => "-c CERT_PATH",
30
+ :long => "--cert-install CERT_PATH",
31
+ :description => "Adds specified certificate to the Windows Certificate Store's Local Machine personal store before creating listener."
32
+
33
+ option :port,
34
+ :short => "-p PORT",
35
+ :long => "--port PORT",
36
+ :description => "Specify port. Default is 5986",
37
+ :default => "5986"
38
+
39
+ option :hostname,
40
+ :short => "-h HOSTNAME",
41
+ :long => "--hostname HOSTNAME",
42
+ :description => "Hostname on the listener. Default is blank",
43
+ :default => ""
44
+
45
+ option :cert_thumbprint,
46
+ :short => "-t THUMBPRINT",
47
+ :long => "--cert-thumbprint THUMBPRINT",
48
+ :description => "Thumbprint of the certificate. Required only if --cert-install option is not used."
49
+
50
+ option :cert_passphrase,
51
+ :short => "-cp PASSWORD",
52
+ :long => "--cert-passphrase PASSWORD",
53
+ :description => "Password for certificate."
54
+
55
+ def get_cert_passphrase
56
+ print "Enter given certificate's passphrase (empty for no passphrase):"
57
+ passphrase = STDIN.gets
58
+ passphrase.strip
59
+ end
60
+
61
+ def run
62
+ STDOUT.sync = STDERR.sync = true
63
+
64
+ if Chef::Platform.windows?
65
+ begin
66
+ if config[:cert_install]
67
+ config[:cert_passphrase] = get_cert_passphrase unless config[:cert_passphrase]
68
+ result = %x{powershell.exe -Command " '#{config[:cert_passphrase]}' | certutil -importPFX '#{config[:cert_install]}' AT_KEYEXCHANGE"}
69
+ if $?.exitstatus
70
+ ui.info "Certificate installed to Certificate Store"
71
+ result = %x{powershell.exe -Command " echo (Get-PfxCertificate #{config[:cert_install]}).thumbprint "}
72
+ ui.info "Certificate Thumbprint: #{result}"
73
+ config[:cert_thumbprint] = result.strip
74
+ else
75
+ ui.error "Error installing certificate to Certificate Store"
76
+ ui.error result
77
+ exit 1
78
+ end
79
+ end
80
+
81
+ unless config[:cert_thumbprint]
82
+ ui.error "Please specify the --cert-thumbprint"
83
+ exit 1
84
+ end
85
+
86
+ result = %x{winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="#{config[:hostname]}";CertificateThumbprint="#{config[:cert_thumbprint]}";Port="#{config[:port]}"}}
87
+ Chef::Log.debug result
88
+
89
+ if ($?.exitstatus == 0)
90
+ ui.info "WinRM listener created with Port: #{config[:port]} and CertificateThumbprint: #{config[:cert_thumbprint]}"
91
+ else
92
+ ui.error "Error creating WinRM listener. use -VV for more details."
93
+ exit 1
94
+ end
95
+
96
+ rescue => e
97
+ puts "ERROR: + #{e}"
98
+ end
99
+ else
100
+ ui.error "WinRM listener can be created on Windows system only"
101
+ exit 1
102
+ end
103
+ end
104
+
105
+ end
106
+ end
107
+ end
@@ -1,212 +1,122 @@
1
- #
2
- # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
- # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- require 'chef/knife'
20
- require 'chef/knife/winrm_knife_base'
21
- require 'chef/knife/windows_cert_generate'
22
- require 'chef/knife/windows_cert_install'
23
- require 'chef/knife/windows_listener_create'
24
- require 'chef/knife/winrm_session'
25
- require 'chef/knife/knife_windows_base'
26
-
27
- class Chef
28
- class Knife
29
- class Winrm < Knife
30
-
31
- include Chef::Knife::WinrmCommandSharedFunctions
32
- include Chef::Knife::KnifeWindowsBase
33
-
34
- FAILED_BASIC_HINT ||= "Hint: Please check winrm configuration 'winrm get winrm/config/service' AllowUnencrypted flag on remote server."
35
- FAILED_NOT_BASIC_HINT ||= <<-eos.gsub /^\s+/, ""
36
- Hint: Make sure to prefix domain usernames with the correct domain name.
37
- Hint: Local user names should be prefixed with computer name or IP address.
38
- EXAMPLE: my_domain\\user_namer
39
- eos
40
-
41
- deps do
42
- require 'readline'
43
- require 'chef/search/query'
44
- end
45
-
46
- attr_writer :password
47
-
48
- banner "knife winrm QUERY COMMAND (options)"
49
-
50
- option :returns,
51
- :long => "--returns CODES",
52
- :description => "A comma delimited list of return codes which indicate success",
53
- :default => "0"
54
-
55
- def run
56
- STDOUT.sync = STDERR.sync = true
57
-
58
- configure_session
59
- validate_password
60
- execute_remote_command
61
- end
62
-
63
- def execute_remote_command
64
- begin
65
- case @name_args[1]
66
- when "interactive"
67
- interactive
68
- else
69
- relay_winrm_command(@name_args[1..-1].join(" "))
70
-
71
- if config[:returns]
72
- check_for_errors!
73
- end
74
-
75
- # Knife seems to ignore the return value of this method,
76
- # so we exit to force the process exit code for this
77
- # subcommand if returns is set
78
- exit @exit_code if @exit_code && @exit_code != 0
79
- @exit_code || 0
80
- end
81
- rescue WinRM::WinRMHTTPTransportError, WinRM::WinRMAuthorizationError => e
82
- if authorization_error?(e)
83
- if ! config[:suppress_auth_failure]
84
- # Display errors if the caller hasn't opted to retry
85
- ui.error "Failed to authenticate to #{@name_args[0].split(" ")} as #{locate_config_value(:winrm_user)}"
86
- ui.info "Response: #{e.message}"
87
- ui.info get_failed_authentication_hint
88
- raise e
89
- end
90
- @exit_code = 401
91
- else
92
- raise e
93
- end
94
- end
95
- end
96
-
97
- def relay_winrm_command(command)
98
- Chef::Log.debug(command)
99
- @winrm_sessions.each do |s|
100
- s.relay_command(command)
101
- end
102
- end
103
-
104
- # TODO: Copied from Knife::Core:GenericPresenter. Should be extracted
105
- def extract_nested_value(data, nested_value_spec)
106
- nested_value_spec.split(".").each do |attr|
107
- if data.nil?
108
- nil # don't get no method error on nil
109
- elsif data.respond_to?(attr.to_sym)
110
- data = data.send(attr.to_sym)
111
- elsif data.respond_to?(:[])
112
- data = data[attr]
113
- else
114
- data = begin
115
- data.send(attr.to_sym)
116
- rescue NoMethodError
117
- nil
118
- end
119
- end
120
- end
121
- ( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
122
- end
123
-
124
- private
125
-
126
- def interactive
127
- puts "WARN: Deprecated functionality. This will not be supported in future knife-windows releases."
128
- puts "Connected to #{ui.list(session.servers.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}"
129
- puts
130
- puts "To run a command on a list of servers, do:"
131
- puts " on SERVER1 SERVER2 SERVER3; COMMAND"
132
- puts " Example: on latte foamy; echo foobar"
133
- puts
134
- puts "To exit interactive mode, use 'quit!'"
135
- puts
136
- while 1
137
- command = read_line
138
- case command
139
- when 'quit!'
140
- puts 'Bye!'
141
- break
142
- when /^on (.+?); (.+)$/
143
- raw_list = $1.split(" ")
144
- server_list = Array.new
145
- @winrm_sessions.each do |session_server|
146
- server_list << session_server if raw_list.include?(session_server.host)
147
- end
148
- command = $2
149
- relay_winrm_command(command, server_list)
150
- else
151
- relay_winrm_command(command)
152
- end
153
- end
154
- end
155
-
156
- def check_for_errors!
157
- @winrm_sessions.each do |session|
158
- session_exit_code = session.exit_code
159
- unless success_return_codes.include? session_exit_code.to_i
160
- @exit_code = session_exit_code.to_i
161
- ui.error "Failed to execute command on #{session.host} return code #{session_exit_code}"
162
- end
163
- end
164
- end
165
-
166
- # Present the prompt and read a single line from the console. It also
167
- # detects ^D and returns "exit" in that case. Adds the input to the
168
- # history, unless the input is empty. Loops repeatedly until a non-empty
169
- # line is input.
170
- def read_line
171
- loop do
172
- command = reader.readline("#{ui.color('knife-winrm>', :bold)} ", true)
173
-
174
- if command.nil?
175
- command = "exit"
176
- puts(command)
177
- else
178
- command.strip!
179
- end
180
-
181
- unless command.empty?
182
- return command
183
- end
184
- end
185
- end
186
-
187
- def reader
188
- Readline
189
- end
190
-
191
- def authorization_error?(exception)
192
- exception.is_a?(WinRM::WinRMAuthorizationError) ||
193
- exception.message =~ /401/
194
- end
195
-
196
- def success_return_codes
197
- #Redundant if the CLI options parsing occurs
198
- return [0] unless config[:returns]
199
- return @success_return_codes ||= config[:returns].split(',').collect {|item| item.to_i}
200
- end
201
-
202
- def get_failed_authentication_hint
203
- if @session_opts[:basic_auth_only]
204
- FAILED_BASIC_HINT
205
- else
206
- FAILED_NOT_BASIC_HINT
207
- end
208
- end
209
- end
210
- end
211
- end
212
-
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife'
20
+ require 'chef/knife/winrm_knife_base'
21
+ require 'chef/knife/windows_cert_generate'
22
+ require 'chef/knife/windows_cert_install'
23
+ require 'chef/knife/windows_listener_create'
24
+ require 'chef/knife/winrm_session'
25
+ require 'chef/knife/knife_windows_base'
26
+
27
+ class Chef
28
+ class Knife
29
+ class Winrm < Knife
30
+
31
+ include Chef::Knife::WinrmCommandSharedFunctions
32
+ include Chef::Knife::KnifeWindowsBase
33
+
34
+ deps do
35
+ require 'readline'
36
+ require 'chef/search/query'
37
+ end
38
+
39
+ attr_writer :password
40
+
41
+ banner "knife winrm QUERY COMMAND (options)"
42
+
43
+ option :returns,
44
+ :long => "--returns CODES",
45
+ :description => "A comma delimited list of return codes which indicate success",
46
+ :default => "0"
47
+
48
+ def run
49
+ STDOUT.sync = STDERR.sync = true
50
+
51
+ configure_session
52
+ execute_remote_command
53
+ end
54
+
55
+ def execute_remote_command
56
+ case @name_args[1]
57
+ when "interactive"
58
+ interactive
59
+ else
60
+ run_command(@name_args[1..-1].join(" "))
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def interactive
67
+ puts "WARN: Deprecated functionality. This will not be supported in future knife-windows releases."
68
+ puts "Connected to #{ui.list(session.servers.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}"
69
+ puts
70
+ puts "To run a command on a list of servers, do:"
71
+ puts " on SERVER1 SERVER2 SERVER3; COMMAND"
72
+ puts " Example: on latte foamy; echo foobar"
73
+ puts
74
+ puts "To exit interactive mode, use 'quit!'"
75
+ puts
76
+ while 1
77
+ command = read_line
78
+ case command
79
+ when 'quit!'
80
+ puts 'Bye!'
81
+ break
82
+ when /^on (.+?); (.+)$/
83
+ raw_list = $1.split(" ")
84
+ server_list = Array.new
85
+ @winrm_sessions.each do |session_server|
86
+ server_list << session_server if raw_list.include?(session_server.host)
87
+ end
88
+ command = $2
89
+ relay_winrm_command(command, server_list)
90
+ else
91
+ relay_winrm_command(command)
92
+ end
93
+ end
94
+ end
95
+
96
+ # Present the prompt and read a single line from the console. It also
97
+ # detects ^D and returns "exit" in that case. Adds the input to the
98
+ # history, unless the input is empty. Loops repeatedly until a non-empty
99
+ # line is input.
100
+ def read_line
101
+ loop do
102
+ command = reader.readline("#{ui.color('knife-winrm>', :bold)} ", true)
103
+
104
+ if command.nil?
105
+ command = "exit"
106
+ puts(command)
107
+ else
108
+ command.strip!
109
+ end
110
+
111
+ unless command.empty?
112
+ return command
113
+ end
114
+ end
115
+ end
116
+
117
+ def reader
118
+ Readline
119
+ end
120
+ end
121
+ end
122
+ end