winrm 1.8.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -11
  3. data/.rubocop.yml +26 -22
  4. data/.travis.yml +11 -12
  5. data/Gemfile +3 -9
  6. data/LICENSE +202 -202
  7. data/README.md +232 -215
  8. data/Rakefile +34 -36
  9. data/Vagrantfile +6 -9
  10. data/WinrmAppveyor.psm1 +31 -31
  11. data/appveyor.yml +51 -51
  12. data/bin/rwinrm +97 -97
  13. data/changelog.md +86 -86
  14. data/lib/winrm.rb +39 -42
  15. data/lib/winrm/connection.rb +82 -0
  16. data/lib/winrm/connection_opts.rb +87 -0
  17. data/lib/winrm/{exceptions/exceptions.rb → exceptions.rb} +76 -57
  18. data/lib/winrm/http/response_handler.rb +96 -82
  19. data/lib/winrm/http/transport.rb +424 -435
  20. data/lib/winrm/http/transport_factory.rb +68 -0
  21. data/lib/winrm/output.rb +59 -43
  22. data/lib/winrm/psrp/create_pipeline.xml.erb +167 -0
  23. data/lib/winrm/psrp/fragment.rb +70 -0
  24. data/lib/winrm/psrp/init_runspace_pool.xml.erb +224 -0
  25. data/lib/winrm/psrp/message.rb +130 -0
  26. data/lib/winrm/psrp/message_data.rb +41 -0
  27. data/lib/winrm/psrp/message_data/base.rb +49 -0
  28. data/lib/winrm/psrp/message_data/error_record.rb +68 -0
  29. data/lib/winrm/psrp/message_data/pipeline_host_call.rb +32 -0
  30. data/lib/winrm/psrp/message_data/pipeline_output.rb +49 -0
  31. data/lib/winrm/psrp/message_data/runspacepool_host_call.rb +32 -0
  32. data/lib/winrm/psrp/message_data/runspacepool_state.rb +39 -0
  33. data/lib/winrm/psrp/message_data/session_capability.rb +36 -0
  34. data/lib/winrm/psrp/message_defragmenter.rb +62 -0
  35. data/lib/winrm/psrp/message_factory.rb +75 -0
  36. data/lib/winrm/psrp/message_fragmenter.rb +60 -0
  37. data/lib/winrm/psrp/powershell_output_decoder.rb +120 -0
  38. data/lib/winrm/psrp/receive_response_reader.rb +93 -0
  39. data/lib/winrm/psrp/session_capability.xml.erb +7 -0
  40. data/lib/winrm/psrp/uuid.rb +40 -0
  41. data/lib/winrm/shells/base.rb +175 -0
  42. data/lib/winrm/shells/cmd.rb +65 -0
  43. data/lib/winrm/shells/power_shell.rb +201 -0
  44. data/lib/winrm/shells/retryable.rb +45 -0
  45. data/lib/winrm/shells/shell_factory.rb +50 -0
  46. data/lib/winrm/version.rb +7 -7
  47. data/lib/winrm/wsmv/base.rb +59 -0
  48. data/lib/winrm/wsmv/cleanup_command.rb +61 -0
  49. data/lib/winrm/wsmv/close_shell.rb +50 -0
  50. data/lib/winrm/wsmv/command.rb +101 -0
  51. data/lib/winrm/wsmv/command_output.rb +76 -0
  52. data/lib/winrm/wsmv/command_output_decoder.rb +55 -0
  53. data/lib/winrm/wsmv/configuration.rb +46 -0
  54. data/lib/winrm/wsmv/create_pipeline.rb +66 -0
  55. data/lib/winrm/wsmv/create_shell.rb +119 -0
  56. data/lib/winrm/wsmv/header.rb +203 -0
  57. data/lib/winrm/wsmv/init_runspace_pool.rb +95 -0
  58. data/lib/winrm/wsmv/iso8601_duration.rb +60 -0
  59. data/lib/winrm/wsmv/keep_alive.rb +68 -0
  60. data/lib/winrm/wsmv/receive_response_reader.rb +128 -0
  61. data/lib/winrm/wsmv/send_data.rb +68 -0
  62. data/lib/winrm/wsmv/soap.rb +51 -0
  63. data/lib/winrm/wsmv/wql_query.rb +79 -0
  64. data/lib/winrm/wsmv/write_stdin.rb +88 -0
  65. data/preamble +17 -17
  66. data/{spec → tests/integration}/auth_timeout_spec.rb +18 -16
  67. data/{spec → tests/integration}/cmd_spec.rb +104 -102
  68. data/{spec → tests/integration}/config-example.yml +16 -19
  69. data/{spec → tests/integration}/issue_59_spec.rb +26 -23
  70. data/tests/integration/powershell_spec.rb +154 -0
  71. data/{spec → tests/integration}/spec_helper.rb +65 -73
  72. data/{spec → tests/integration}/transport_spec.rb +99 -139
  73. data/{spec → tests/integration}/wql_spec.rb +16 -14
  74. data/{spec → tests}/matchers.rb +60 -74
  75. data/tests/spec/configuration_spec.rb +93 -0
  76. data/tests/spec/connection_spec.rb +39 -0
  77. data/{spec → tests/spec}/exception_spec.rb +50 -50
  78. data/tests/spec/http/transport_factory_spec.rb +68 -0
  79. data/tests/spec/http/transport_spec.rb +44 -0
  80. data/{spec → tests/spec}/output_spec.rb +127 -110
  81. data/tests/spec/psrp/fragment_spec.rb +62 -0
  82. data/tests/spec/psrp/message_data/base_spec.rb +13 -0
  83. data/tests/spec/psrp/message_data/error_record_spec.rb +41 -0
  84. data/tests/spec/psrp/message_data/pipeline_host_call_spec.rb +25 -0
  85. data/tests/spec/psrp/message_data/pipeline_output_spec.rb +32 -0
  86. data/tests/spec/psrp/message_data/runspace_pool_host_call_spec.rb +25 -0
  87. data/tests/spec/psrp/message_data/runspacepool_state_spec.rb +16 -0
  88. data/tests/spec/psrp/message_data/session_capability_spec.rb +30 -0
  89. data/tests/spec/psrp/message_data_spec.rb +35 -0
  90. data/tests/spec/psrp/message_defragmenter_spec.rb +47 -0
  91. data/tests/spec/psrp/message_fragmenter_spec.rb +105 -0
  92. data/tests/spec/psrp/powershell_output_decoder_spec.rb +84 -0
  93. data/tests/spec/psrp/psrp_message_spec.rb +70 -0
  94. data/tests/spec/psrp/recieve_response_reader_spec.rb +154 -0
  95. data/tests/spec/psrp/uuid_spec.rb +28 -0
  96. data/{spec → tests/spec}/response_handler_spec.rb +61 -61
  97. data/tests/spec/shells/base_spec.rb +202 -0
  98. data/tests/spec/shells/cmd_spec.rb +75 -0
  99. data/tests/spec/shells/powershell_spec.rb +175 -0
  100. data/tests/spec/spec_helper.rb +47 -0
  101. data/tests/spec/stubs/clixml/error_record.xml.erb +84 -0
  102. data/{spec → tests/spec}/stubs/responses/get_command_output_response.xml.erb +13 -13
  103. data/tests/spec/stubs/responses/get_command_output_response_not_done.xml.erb +10 -0
  104. data/tests/spec/stubs/responses/get_powershell_keepalive_response.xml.erb +10 -0
  105. data/tests/spec/stubs/responses/get_powershell_output_response.xml.erb +12 -0
  106. data/tests/spec/stubs/responses/get_powershell_output_response_not_done.xml.erb +9 -0
  107. data/{spec → tests/spec}/stubs/responses/open_shell_v1.xml +19 -19
  108. data/{spec → tests/spec}/stubs/responses/open_shell_v2.xml +20 -20
  109. data/{spec → tests/spec}/stubs/responses/soap_fault_v1.xml +36 -36
  110. data/{spec → tests/spec}/stubs/responses/soap_fault_v2.xml +42 -42
  111. data/{spec → tests/spec}/stubs/responses/wmi_error_v2.xml +41 -41
  112. data/tests/spec/wsmv/cleanup_command_spec.rb +22 -0
  113. data/tests/spec/wsmv/close_shell_spec.rb +17 -0
  114. data/{spec → tests/spec/wsmv}/command_output_decoder_spec.rb +37 -37
  115. data/tests/spec/wsmv/command_output_spec.rb +45 -0
  116. data/tests/spec/wsmv/command_spec.rb +19 -0
  117. data/tests/spec/wsmv/configuration_spec.rb +17 -0
  118. data/tests/spec/wsmv/create_pipeline_spec.rb +31 -0
  119. data/tests/spec/wsmv/create_shell_spec.rb +38 -0
  120. data/tests/spec/wsmv/init_runspace_pool_spec.rb +36 -0
  121. data/tests/spec/wsmv/keep_alive_spec.rb +21 -0
  122. data/tests/spec/wsmv/receive_response_reader_spec.rb +123 -0
  123. data/tests/spec/wsmv/send_data_spec.rb +30 -0
  124. data/tests/spec/wsmv/wql_query_spec.rb +13 -0
  125. data/tests/spec/wsmv/write_stdin_spec.rb +22 -0
  126. data/winrm.gemspec +42 -40
  127. metadata +140 -38
  128. data/.rspec +0 -3
  129. data/lib/winrm/command_executor.rb +0 -243
  130. data/lib/winrm/command_output_decoder.rb +0 -53
  131. data/lib/winrm/helpers/iso8601_duration.rb +0 -58
  132. data/lib/winrm/helpers/powershell_script.rb +0 -42
  133. data/lib/winrm/soap_provider.rb +0 -39
  134. data/lib/winrm/winrm_service.rb +0 -550
  135. data/spec/command_executor_spec.rb +0 -475
  136. data/spec/issue_184_spec.rb +0 -67
  137. data/spec/powershell_spec.rb +0 -97
  138. data/spec/winrm_options_spec.rb +0 -76
  139. data/spec/winrm_primitives_spec.rb +0 -51
data/README.md CHANGED
@@ -1,215 +1,232 @@
1
- # Windows Remote Management (WinRM) for Ruby
2
- [![Build Status](https://travis-ci.org/WinRb/WinRM.svg?branch=master)](https://travis-ci.org/WinRb/WinRM)
3
- [![Gem Version](https://badge.fury.io/rb/winrm.svg)](http://badge.fury.io/rb/winrm)
4
- [![Build status](https://ci.appveyor.com/api/projects/status/ods9tvos78k5c15h?svg=true)](https://ci.appveyor.com/project/winrb/winrm)
5
-
6
- This is a SOAP library that uses the functionality in Windows Remote
7
- Management(WinRM) to call native object in Windows. This includes, but is
8
- not limitted to, running batch scripts, powershell scripts and fetching WMI
9
- variables. For more information on WinRM, please visit Microsoft's WinRM
10
- site: http://msdn.microsoft.com/en-us/library/aa384426(v=VS.85).aspx
11
-
12
- ## Supported WinRM Versions
13
- WinRM 1.1 is supported, however 2.0 and higher is recommended. [See MSDN](http://technet.microsoft.com/en-us/library/ff520073(v=ws.10).aspx) for information about WinRM versions and supported operating systems.
14
-
15
- ## Install
16
- `gem install -r winrm` then on the server `winrm quickconfig` as admin
17
-
18
- ## Example
19
- ```ruby
20
- require 'winrm'
21
- endpoint = 'http://mywinrmhost:5985/wsman'
22
- krb5_realm = 'EXAMPLE.COM'
23
- winrm = WinRM::WinRMWebService.new(endpoint, :kerberos, :realm => krb5_realm)
24
- winrm.create_executor do |executor|
25
- executor.run_cmd('ipconfig /all') do |stdout, stderr|
26
- STDOUT.print stdout
27
- STDERR.print stderr
28
- end
29
- end
30
- ```
31
-
32
- There are various connection types you can specify upon initialization:
33
-
34
- It is recommended that you <code>:disable_sspi => true</code> if you are using the plaintext or ssl transport.
35
-
36
- ### Deprecated methods
37
- As of version 1.5.0 `WinRM::WinRMWebService` methods `cmd`, `run_cmd`, `powershell`, and `run_powershell_script` have been deprecated and will be removed from the next major version of the WinRM gem.
38
-
39
- Use the `run_cmd` and `run_powershell_script` of the `WinRM::CommandExecutor` class instead. The `CommandExecutor` allows multiple commands to be run from the same WinRM shell providing a significant performance improvement when issuing multiple calls.
40
-
41
- #### NTLM/Negotiate
42
- ```ruby
43
- winrm = WinRM::WinRMWebService.new(endpoint, :negotiate, :user => myuser, :pass => mypass)
44
- ```
45
-
46
- #### Plaintext
47
- Note: It is strongly recommended that you use `:negotiate` instead of `:plaintext`. As the name infers, the `:plaintext` transport includes authentication credentials in plain text.
48
- ```ruby
49
- WinRM::WinRMWebService.new(endpoint, :plaintext, :user => myuser, :pass => mypass, :disable_sspi => true)
50
-
51
- ## Same but force basic authentication:
52
- WinRM::WinRMWebService.new(endpoint, :plaintext, :user => myuser, :pass => mypass, :basic_auth_only => true)
53
- ```
54
-
55
- #### SSL
56
- ```ruby
57
- WinRM::WinRMWebService.new(endpoint, :ssl, :user => myuser, :pass => mypass, :disable_sspi => true)
58
-
59
- # Specifying CA path
60
- WinRM::WinRMWebService.new(endpoint, :ssl, :user => myuser, :pass => mypass, :ca_trust_path => '/etc/ssl/certs/cert.pem', :basic_auth_only => true)
61
-
62
- # Same but force basic authentication:
63
- WinRM::WinRMWebService.new(endpoint, :ssl, :user => myuser, :pass => mypass, :basic_auth_only => true)
64
-
65
- # Basic auth over SSL w/self signed cert
66
- # Enabling no_ssl_peer_verification is not recommended. HTTPS connections are still encrypted,
67
- # but the WinRM gem is not able to detect forged replies or man in the middle attacks.
68
- WinRM::WinRMWebService.new(endpoint, :ssl, :user => myuser, :pass => mypass, :basic_auth_only => true, :no_ssl_peer_verification => true)
69
-
70
- # Verify against a known fingerprint
71
- WinRM::WinRMWebService.new(endpoint, :ssl, :user => myuser, :pass => mypass, :basic_auth_only => true, :ssl_peer_fingerprint => '6C04B1A997BA19454B0CD31C65D7020A6FC2669D')
72
-
73
- # Specifying a Client Cert, key and (optional) key password for password-less authentication
74
- WinRM::WinRMWebService.new(endpoint, :ssl, :client_cert => '/path/to/cert.pem', :client_key => '/path/to/key.key', :key_pass => 'password', :no_ssl_peer_verification => true)
75
-
76
- # Specifying a Client Cert object, key object and (optional) key password for password-less authentication
77
- WinRM::WinRMWebService.new(endpoint, :ssl, :client_cert => <X509::Certificate object>, :client_key => <PKey::Pkey object>, :key_pass => 'password', :no_ssl_peer_verification => true)
78
- ```
79
-
80
- ##### Create a self signed cert for WinRM
81
- You may want to create a self signed certificate for servicing https WinRM connections. You can use the following PowerShell script to create a cert and enable the WinRM HTTPS listener. Unless you are running windows server 2012 R2 or later, you must install makecert.exe from the Windows SDK, otherwise use `New-SelfSignedCertificate`.
82
-
83
- ```powershell
84
- $hostname = $Env:ComputerName
85
-
86
- C:\"Program Files"\"Microsoft SDKs"\Windows\v7.1\Bin\makecert.exe -r -pe -n "CN=$hostname,O=vagrant" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 "$hostname.cer"
87
-
88
- $thumbprint = (& ls cert:LocalMachine/my).Thumbprint
89
-
90
- # Windows 2012R2 and above can use New-SelfSignedCertificate
91
- $thumbprint = (New-SelfSignedCertificate -DnsName $hostname -CertStoreLocation cert:\LocalMachine\my).Thumbprint
92
-
93
- $cmd = "winrm create winrm/config/Listener?Address=*+Transport=HTTPS '@{Hostname=`"$hostname`";CertificateThumbprint=`"$thumbprint`"}'"
94
- iex $cmd
95
- ```
96
-
97
- ##### Setting up Certificate based authentication
98
- Perform the following steps to authenticate with a certificate instead of a username and password:
99
-
100
- 1. Generate a certificate with an Extended Key Usage of Client Authentication and a Subject Alternative Name with the UPN of the user. See this [powershell function](https://github.com/WinRb/WinRM/blob/master/WinrmAppveyor.psm1#L1) as an example of using `openssl` to create a self signed user certificate in `.pem` and `.pfx` formats along with the private key file.
101
-
102
- 2. Import the pfx file into the `TrustedPeople` directory of the `LocalMachine` certificate store on the windows endpoint.
103
-
104
- 3. Import the issuing certificate authority certificate in the endpoint's `Root` certificates. If your client certificate is self signed, this will be the client certificate.
105
-
106
- 4. Enable certificate authentication on the endpoint: `Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true`
107
-
108
- 5. Add a winrm user mapping for the issuing certificate: `New-Item -Path WSMan:\localhost\ClientCertificate -Subject <user UPN> -URI * -Issuer <issuing certificate thumbprint> -Credential (Get-Credential) -Force`
109
-
110
- See [this post](http://www.hurryupandwait.io/blog/certificate-password-less-based-authentication-in-winrm) for more details on certificate authentication.
111
-
112
- #### Kerberos
113
- ```ruby
114
- WinRM::WinRMWebService.new(endpoint, :kerberos, :realm => 'MYREALM.COM')
115
- ```
116
-
117
- ## Retries and opening a shell
118
- Especially if provisioning a new machine, it's possible the winrm service is not yet running when first attempting to connect. The `WinRMWebService` accepts the options `:retry_limit` and `:retry_delay` to specify the maximum number of attempts to make and how long to wait in between. These default to 3 attempts and a 10 second delay.
119
- ```ruby
120
- WinRM::WinRMWebService.new(endpoint, :ssl, :user => myuser, :pass => mypass, :retry_limit => 30, :retry_delay => 10)
121
- ```
122
-
123
- ## Logging
124
- The `WinRMWebService` exposes a `logger` attribute and uses the [logging](https://rubygems.org/gems/logging) gem to manage logging behavior. By default this appends to `STDOUT` and has a level of `:warn`, but one can adjust the level or add additional appenders.
125
- ```ruby
126
- winrm = WinRM::WinRMWebService.new(endpoint, :ssl, :user => myuser, :pass => mypass)
127
-
128
- # suppress warnings
129
- winrm.logger.level = :error
130
-
131
- # Log to a file
132
- winrm.logger.add_appenders(Logging.appenders.file('error.log'))
133
- ```
134
-
135
- If a consuming application uses its own logger that complies to the logging API, you can simply swap it in:
136
- ```ruby
137
- winrm.logger = my_logger
138
- ```
139
-
140
- ## Troubleshooting
141
- You may have some errors like ```WinRM::WinRMAuthorizationError```.
142
- You can run the following commands on the server to try to solve the problem:
143
- ```
144
- winrm set winrm/config/client/auth @{Basic="true"}
145
- winrm set winrm/config/service/auth @{Basic="true"}
146
- winrm set winrm/config/service @{AllowUnencrypted="true"}
147
- ```
148
- You can read more about that on issue [#29](https://github.com/WinRb/WinRM/issues/29)
149
-
150
- Also see [this post](http://www.hurryupandwait.io/blog/understanding-and-troubleshooting-winrm-connection-and-authentication-a-thrill-seekers-guide-to-adventure) for more general tips related to winrm connection and authentication issues.
151
-
152
-
153
- ## Current features
154
-
155
- 1. GSSAPI support: This is the default way that Windows authenticates and
156
- secures WinRM messages. In order for this to work the computer you are
157
- connecting to must be a part of an Active Directory domain and you must
158
- have local credentials via kinit. GSSAPI support is dependent on the
159
- gssapi gem which only supports the MIT Kerberos libraries at this time.
160
-
161
- If you are using this method there is no longer a need to change the
162
- WinRM service authentication settings. You can simply do a
163
- 'winrm quickconfig' on your server or enable WinRM via group policy and
164
- everything should be working.
165
-
166
- 2. Multi-Instance support: Moving away from Handsoap allows multiple
167
- instances to be created because the SOAP backend is no longer a Singleton
168
- type class.
169
-
170
- 3. 100% Ruby: Nokogiri while faster can present additional frustration for
171
- users above and beyond what is already required to get WinRM working.
172
- The goal of this gem is make using WinRM easy. In V2 we plan on making
173
- the parser swappable in case you really do need the performance.
174
-
175
- ## Contributing
176
-
177
- 1. Fork it.
178
- 2. Create a branch (git checkout -b my_feature_branch)
179
- 3. Run the unit and integration tests (bundle exec rake integration)
180
- 4. Commit your changes (git commit -am "Added a sweet feature")
181
- 5. Push to the branch (git push origin my_feature_branch)
182
- 6. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
183
-
184
- ### Running the tests
185
-
186
- We use Bundler to manage dependencies during development.
187
-
188
- ```
189
- $ bundle install
190
- ```
191
-
192
- Once you have the dependencies, you can run the unit tests with `rake`:
193
-
194
- ```
195
- $ bundle exec rake spec
196
- ```
197
-
198
- To run the integration tests you will need a Windows box with the WinRM service properly configured. Its easiest to use a Vagrant Windows box (mwrock/Windows2012R2 is public on [atlas](https://atlas.hashicorp.com/mwrock/boxes/Windows2012R2) with an evaluation version of Windows 2012 R2).
199
-
200
- 1. Create a Windows VM with WinRM configured (see above).
201
- 2. Copy the config-example.yml to config.yml - edit this file with your WinRM connection details.
202
- 3. Ensure that the box you are running the test against has a default shell profile (check ~\Documents\WindowsPowerShell). If any of your shell profiles generate stdout or stderr output, the test validators may get thrown off.
203
- 4. Run `bundle exec rake integration`
204
-
205
- ## WinRM Author
206
- * Twitter: [@zentourist](https://twitter.com/zentourist)
207
- * BLOG: [http://distributed-frostbite.blogspot.com/](http://distributed-frostbite.blogspot.com/)
208
- * Add me in LinkedIn: [http://www.linkedin.com/in/danwanek](http://www.linkedin.com/in/danwanek)
209
- * Find me on irc.freenode.net in #ruby-lang (zenChild)
210
-
211
- ## Maintainers
212
- * Paul Morton (https://github.com/pmorton)
213
- * Shawn Neal (https://github.com/sneal)
214
-
215
- [Contributors](https://github.com/WinRb/WinRM/graphs/contributors)
1
+ # Windows Remote Management (WinRM) for Ruby
2
+ [![Build Status](https://travis-ci.org/WinRb/WinRM.svg?branch=master)](https://travis-ci.org/WinRb/WinRM)
3
+ [![Gem Version](https://badge.fury.io/rb/winrm.svg)](http://badge.fury.io/rb/winrm)
4
+ [![Build status](https://ci.appveyor.com/api/projects/status/ods9tvos78k5c15h?svg=true)](https://ci.appveyor.com/project/winrb/winrm)
5
+
6
+ This is a SOAP library that uses the functionality in Windows Remote
7
+ Management(WinRM) to call native object in Windows. This includes, but is
8
+ not limited to, running batch scripts, powershell scripts and fetching WMI
9
+ variables. For more information on WinRM, please visit [Microsoft's WinRM
10
+ site](http://msdn.microsoft.com/en-us/library/aa384426.aspx).
11
+
12
+ As of version 2.0, this gem retains the WinRM name but all powershell calls use the more modern [Powershell Remoting Protocol (PSRP)](https://msdn.microsoft.com/en-us/library/dd357801.aspx) for initializing runspace pools as well as creating and processing powershell pipelines.
13
+
14
+ ## Supported WinRM Versions
15
+ WinRM 1.1 is supported, however 2.0 and higher is recommended. [See MSDN](http://technet.microsoft.com/en-us/library/ff520073.aspx) for information about WinRM versions and supported operating systems.
16
+
17
+ ## Install
18
+ `gem install -r winrm` then on the server `Enable-PSRemoting -Force` (already enabled on server operating systems 2012 and above) as admin
19
+
20
+ ## Example
21
+ ```ruby
22
+ require 'winrm'
23
+ opts = {
24
+ endpoint: 'http://myhost:5985/wsman',
25
+ user: 'administrator',
26
+ password: 'Pass@word1'
27
+ }
28
+ conn = WinRM::Connection.new(opts)
29
+ conn.shell(:powershell) do |shell|
30
+ shell.run('$PSVersionTable') do |stdout, stderr|
31
+ STDOUT.print stdout
32
+ STDERR.print stderr
33
+ end
34
+ end
35
+ ```
36
+
37
+ ## Connection Options
38
+ There are various connection options you can specify upon initializing a WinRM connection object:
39
+
40
+ * `:transport` - The type of underlying connection transport to use (more on this below). Defaults to `:negotiate`
41
+ * `:locale` - The locale requested for response text formatting. This is the value sent in the `DataLocale` and `Locale` header values and defaults to `en-us`
42
+ * `:max_envelope_size` - mazimum number of bytes expected for WinRM responses. This defaults to 153600
43
+ * `:operation_timeout` - The maximum amount of time to wait for a response from the endpoint. This defaults to 60 seconds. Note that this will not "timeout" commands that exceed this amount of time to process, it just requires the endpoint to report the status of the command before the given amount of time passes.
44
+ * `:receive_timeout` - The amount of time given to the underlying HTTP connection to respond before timing out. The defaults to 10 seconds longer than the `:operation_timeout`.
45
+ * `:retry_limit` - the maximum number of times to retry opening a shell after failure. This defaults to 3.
46
+ * `:retry_delay` - the amount of time to wait between retries and defaults to 10 seconds
47
+ * `:user` - username used to authenticate over the `:transport`
48
+ * `:password` - password used to authenticate over the `:transport`
49
+
50
+ There are other options that may apply depending on the type of `:transport` used and are discussed below.
51
+
52
+ ## Transports
53
+
54
+ The transport used governs the authentication method used and the encryption level used for the underlying HTTP communication with the endpoint. The WinRM gem supports the following transport types:
55
+
56
+ ### `:negotiate`
57
+ ```ruby
58
+ WinRM::Connection.new(
59
+ endpoint: 'http://myhost:5985/wsman',
60
+ transport: :negotiate,
61
+ user: 'administrator',
62
+ password: 'Pass@word1'
63
+ )
64
+ ```
65
+
66
+ The `:negotiate` transport uses the [rubyntlm gem](https://github.com/WinRb/rubyntlm) to authenticate with the endpoint using the NTLM protocol. This uses an HTTP based connection but the SOAP message payloads are encrypted. If using HTTP (as opposed to HTTPS) this is the recommended transport. This is also the default transport used if none is specified in the connection options.
67
+
68
+ ### `:ssl`
69
+ ```ruby
70
+ WinRM::Connection.new(
71
+ endpoint: 'https://myhost:59856/wsman',
72
+ transport: :ssl,
73
+ user: 'administrator',
74
+ password: 'Pass@word1'
75
+ )
76
+ ```
77
+
78
+ The `:ssl` transport establishes a connection to the winrm endpoint over a secure sockets layer transport encrypting the entire message. Here are some additional connecion options available to `:ssl` connections:
79
+
80
+ * `:client_cert` - Either a string path to a certificate `.pem` file or a `X509::Certificate` object. This along with an accompanying `:client_key` can be used in lieu of a `:user` and `:password`.
81
+ * `:client_key` - the path to the private key file accompanying the above mentioned `:client_cert` or an `PKey::Pkey` object.
82
+ * `:key_pass` - the optional password if necessary to access the `:client_cert`
83
+ * `:no_ssl_peer_verification` - when set to `true` ssl certificate validation is not performed. With a self signed cert, its a match made in heaven!
84
+ * `:ssl_peer_fingerprint` - when this is provided, normal certificate validation is skipped and instead the given fingerprint is matched against the certificate of the endpoint for verification.
85
+ * `:ca_trust_path` - the path to a certificate `.pem` file to trust. Its similar to the `:ssl_peer_fingerprint` but contains the entire certificate to trust.
86
+
87
+ ### `:kerberos`
88
+ ```ruby
89
+ WinRM::Connection.new(
90
+ endpoint: 'http://myhost:5985/wsman',
91
+ transport: :kerberos,
92
+ realm: 'kerberos_realm'
93
+ )
94
+ ```
95
+
96
+ Uses `:kerberos` to authenticate with the endpoint. These additional connection options may be used:
97
+
98
+ * `:service` - kerberos service used to authenticate with the endpoint. Defaults to `HTTP`.
99
+ * `:realm` - Kerberos realm to authenticate against.
100
+
101
+ ### `:plaintext`
102
+ Note: It is strongly recommended that you use `:negotiate` instead of `:plaintext`. As the name infers, the `:plaintext` transport includes authentication credentials in plain text.
103
+ ```ruby
104
+ WinRM::Connection.new(
105
+ endpoint: 'http://myhost:5985/wsman',
106
+ transport: :plaintext,
107
+ user: 'administrator',
108
+ password: 'Pass@word1',
109
+ basic_auth_only: true
110
+ )
111
+ ```
112
+
113
+ Additional supported connection options:
114
+
115
+ * `:basic_auth_only` - Force basic authentication
116
+ * `:disable_sspi` - Disable SSPI Negotiation authentication
117
+
118
+ ## Shells
119
+
120
+ As of the WinRM gem version 2, one creates a shell for executing commands by calling the `shell` method of a WinRM connection. There are two types of shells available:
121
+
122
+ * `:cmd` - initiates a traditional cmd.exe shell via the WinRM protocol
123
+ * `:powershell` - initiates a powershell runspace via the PSRP protocol
124
+
125
+ Both shells support the same public methods: `:open`, `:close`, and `run`. Note that when given a shell, it is opened automatically upon executing the first command via `:run`. Further, `close` is called automatically when a `shell` is garbage collected or when using a shell from a block. However, it is always a good idea to proactively `close` a shell.
126
+
127
+ ## Executing a WQL Query
128
+ ```ruby
129
+ opts = {
130
+ endpoint: 'http://myhost:5985/wsman',
131
+ user: 'administrator',
132
+ password: 'Pass@word1'
133
+ }
134
+ conn = WinRM::Connection.new(opts)
135
+
136
+ out = conn.run_wql('select * from Win32_OperatingSystem')
137
+ output_caption = out[:win32_operating_system][0][:caption]
138
+ ```
139
+
140
+ ## Create a self signed cert for WinRM
141
+ You may want to create a self signed certificate for servicing https WinRM connections. You can use the following PowerShell script to create a cert and enable the WinRM HTTPS listener. Unless you are running windows server 2012 R2 or later, you must install makecert.exe from the Windows SDK, otherwise use `New-SelfSignedCertificate`.
142
+
143
+ ```powershell
144
+ $hostname = $Env:ComputerName
145
+
146
+ C:\"Program Files"\"Microsoft SDKs"\Windows\v7.1\Bin\makecert.exe -r -pe -n "CN=$hostname,O=vagrant" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 "$hostname.cer"
147
+
148
+ $thumbprint = (& ls cert:LocalMachine/my).Thumbprint
149
+
150
+ # Windows 2012R2 and above can use New-SelfSignedCertificate
151
+ $thumbprint = (New-SelfSignedCertificate -DnsName $hostname -CertStoreLocation cert:\LocalMachine\my).Thumbprint
152
+
153
+ $cmd = "winrm create winrm/config/Listener?Address=*+Transport=HTTPS '@{Hostname=`"$hostname`";CertificateThumbprint=`"$thumbprint`"}'"
154
+ iex $cmd
155
+ ```
156
+
157
+ ## Setting up Certificate based authentication
158
+ Perform the following steps to authenticate with a certificate instead of a username and password:
159
+
160
+ 1. Generate a certificate with an Extended Key Usage of Client Authentication and a Subject Alternative Name with the UPN of the user. See this [powershell function](https://github.com/WinRb/WinRM/blob/master/WinrmAppveyor.psm1#L1) as an example of using `openssl` to create a self signed user certificate in `.pem` and `.pfx` formats along with the private key file.
161
+
162
+ 2. Import the pfx file into the `TrustedPeople` directory of the `LocalMachine` certificate store on the windows endpoint.
163
+
164
+ 3. Import the issuing certificate authority certificate in the endpoint's `Root` certificates. If your client certificate is self signed, this will be the client certificate.
165
+
166
+ 4. Enable certificate authentication on the endpoint: `Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true`
167
+
168
+ 5. Add a winrm user mapping for the issuing certificate: `New-Item -Path WSMan:\localhost\ClientCertificate -Subject <user UPN> -URI * -Issuer <issuing certificate thumbprint> -Credential (Get-Credential) -Force`
169
+
170
+ See [this post](http://www.hurryupandwait.io/blog/certificate-password-less-based-authentication-in-winrm) for more details on certificate authentication.
171
+
172
+ ## Logging
173
+ The `WinRM::Connection` exposes a `logger` attribute and uses the [logging](https://rubygems.org/gems/logging) gem to manage logging behavior. By default this appends to `STDOUT` and has a level of `:warn`, but one can adjust the level or add additional appenders.
174
+ ```ruby
175
+ conn = WinRM::Connection.new(opts)
176
+
177
+ # suppress warnings
178
+ conn.logger.level = :error
179
+
180
+ # Log to a file
181
+ conn.logger.add_appenders(Logging.appenders.file('error.log'))
182
+ ```
183
+
184
+ If a consuming application uses its own logger that complies to the logging API, you can simply swap it in:
185
+ ```ruby
186
+ conn.logger = my_logger
187
+ ```
188
+
189
+ ## Troubleshooting
190
+ You may have some errors like ```WinRM::WinRMAuthorizationError```. See [this post](http://www.hurryupandwait.io/blog/understanding-and-troubleshooting-winrm-connection-and-authentication-a-thrill-seekers-guide-to-adventure) for tips and troubleshooting steps related to winrm connection and authentication issues.
191
+
192
+ ## Contributing
193
+
194
+ 1. Fork it.
195
+ 2. Create a branch (git checkout -b my_feature_branch)
196
+ 3. Run the unit and integration tests (bundle exec rake integration)
197
+ 4. Commit your changes (git commit -am "Added a sweet feature")
198
+ 5. Push to the branch (git push origin my_feature_branch)
199
+ 6. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
200
+
201
+ ### Running the tests
202
+
203
+ We use Bundler to manage dependencies during development.
204
+
205
+ ```
206
+ $ bundle install
207
+ ```
208
+
209
+ Once you have the dependencies, you can run the unit tests with `rake`:
210
+
211
+ ```
212
+ $ bundle exec rake spec
213
+ ```
214
+
215
+ To run the integration tests you will need a Windows box with the WinRM service properly configured. Its easiest to use a Vagrant Windows box (mwrock/Windows2012R2 is public on [atlas](https://atlas.hashicorp.com/mwrock/boxes/Windows2012R2) with an evaluation version of Windows 2012 R2). You can also use `mwrock/WindowsNano` provided in this repo's `Vagrantfile`.
216
+
217
+ 1. Create a Windows VM with WinRM configured (see above).
218
+ 2. Copy the config-example.yml to config.yml - edit this file with your WinRM connection details.
219
+ 3. Run `bundle exec rake integration`
220
+
221
+ ## WinRM Author
222
+ * Twitter: [@zentourist](https://twitter.com/zentourist)
223
+ * BLOG: [http://distributed-frostbite.blogspot.com/](http://distributed-frostbite.blogspot.com/)
224
+ * Add me in LinkedIn: [http://www.linkedin.com/in/danwanek](http://www.linkedin.com/in/danwanek)
225
+ * Find me on irc.freenode.net in #ruby-lang (zenChild)
226
+
227
+ ## Maintainers
228
+ * Paul Morton (https://github.com/pmorton)
229
+ * Shawn Neal (https://github.com/sneal)
230
+ * Matt Wrock (https://github.com/mwrock)
231
+
232
+ [Contributors](https://github.com/WinRb/WinRM/graphs/contributors)
data/Rakefile CHANGED
@@ -1,36 +1,34 @@
1
- # encoding: UTF-8
2
- require 'rubygems'
3
- require 'bundler/setup'
4
- require 'rspec/core/rake_task'
5
- require 'rubocop/rake_task'
6
- require 'bundler/gem_tasks'
7
-
8
- # Change to the directory of this file.
9
- Dir.chdir(File.expand_path('../', __FILE__))
10
-
11
- desc 'Open a Pry console for this library'
12
- task :console do
13
- require 'pry'
14
- require 'winrm'
15
- ARGV.clear
16
- Pry.start
17
- end
18
-
19
- RSpec::Core::RakeTask.new(:spec) do |task|
20
- task.pattern = 'spec/*_spec.rb'
21
- task.rspec_opts = ['--color', '-f documentation']
22
- task.rspec_opts << '-tunit'
23
- end
24
-
25
- # Run the integration test suite
26
- RSpec::Core::RakeTask.new(:integration) do |task|
27
- task.pattern = 'spec/*_spec.rb'
28
- task.rspec_opts = ['--color', '-f documentation']
29
- task.rspec_opts << '-tintegration'
30
- end
31
-
32
- RuboCop::RakeTask.new
33
-
34
- task default: [:spec, :rubocop]
35
-
36
- task all: [:default, :integration]
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+ require 'bundler/gem_tasks'
7
+
8
+ # Change to the directory of this file.
9
+ Dir.chdir(File.expand_path('../', __FILE__))
10
+
11
+ desc 'Open a Pry console for this library'
12
+ task :console do
13
+ require 'pry'
14
+ require 'winrm'
15
+ ARGV.clear
16
+ Pry.start
17
+ end
18
+
19
+ RSpec::Core::RakeTask.new(:spec) do |task|
20
+ task.pattern = 'tests/spec/**/*_spec.rb'
21
+ task.rspec_opts = ['--color', '-f documentation', '-r ./tests/spec/spec_helper']
22
+ end
23
+
24
+ # Run the integration test suite
25
+ RSpec::Core::RakeTask.new(:integration) do |task|
26
+ task.pattern = 'tests/integration/*_spec.rb'
27
+ task.rspec_opts = ['--color', '-f documentation', '-r ./tests/integration/spec_helper']
28
+ end
29
+
30
+ RuboCop::RakeTask.new
31
+
32
+ task default: [:spec, :rubocop]
33
+
34
+ task all: [:default, :integration]