=======================
The groovy-winrm-client
is a Groovy-based library for executing commands on a remote (Windows) servers through WinRM. The library allows:
- connecting,
- executing remote command,
- reading output of the execution,
- stopping remote command,
- deleting opened shell on a remote host.
The easiest way to use groovy-winrm-client
in a Groovy script is by importing the dependency using Grape.
@Grab('com.aestasit.infrastructure.winrm:groovy-winrm-client:0.5')
import com.aestasit.infrastructure.winrm.client.WinRMClient
The entry point is the WinRMClient
class. By default WinRMClient
uses HTTP
protocol
with 5985
port for connecting with remote host by WinRM
.
For starting it is necessary to define host name, user and password used to connect to the remote host:
WinRMClient client = new WinRMClient(host: 'hostname', user: 'user', password: 'pwd')
To use the WinRMClient
via HTTPS we need to set corresponding protocol and port.
WinRMClient client = new WinRMClient(protocol: 'https', host: 'hostname', port: 5986, user: 'user', password: 'pwd')
HTTPS
usage required defining trust strategy and verification strategy of the client. By default trust strategy for WinRMClient
is set to TrustStrategy.ALLOW_SELF_SIGNED
and verification strategy is set to HostStrategy.ALLOW_ALL
.
There are also other options available in WinRMClient
for trust strategy TrustStrategy.ALLOW_NONE
and TrustStrategy.ALLOW_ALL
; and for verification strategy HostStrategy.ALLOW_STRICT
, HostStrategy.ALLOW_BROWSER_COMPATIBLE
.
requestTimeout
parameter is important for slow connections. The value defines time within which WinRM request has to be finished. By default this value is set to 60 seconds. If a WinRM request cannot be executed within this time period an error occurred and WinRM request processing is terminated with the corresponding message.
After WinRMClient
object is created it is necessary to open shell on a remote host where commands will be executed:
client.openShell()
After shell is open remote commands are executed
String commandId = client.executeCommand('C:\Windows\System32\cmd.exe', ['/C', 'del /q/f/s %TEMP%\*] as String[])
executeCommand
method returns command id which is used to receive the results of the command execution
CommandOutput output = client.commandExecuteResults(commandId)
output.with{
println exitStatus
println output
println errorOutput
}
CommandOutput
contains
exitStatus
to indicate the results of the invocation of a remote command, in case of succesful finishing the return value is0
output
standard output of the command executionerrorOutput
error details of command executionexception
object contains exceptions occurres during command execution processing on client side
Sometimes command execution requires long time period. When the command is being executed commandExecuteResults()
returns output with exitCode = -1
and errorOutput='Remote command is still running!
. In this case it is necessary to monitor the execution of the remote command in a loop with the simultaneous accumulation of output results. This may be done in a separate thread:
def completeExecOutput = new CommandOutput(-1,'','')
Thread thread = new Thread() {
void run() {
for (; !isInterrupted();) {
def currentOutput = client.commandExecuteResults(commandId)
completeExecOutput.with{
exitStatus = currentOutput.exitStatus
output += currentOutput.output
errorOutput = currentOutput.errorOutput
exception = currentOutput.exception
}
if (!completeExecOutput.commandRunning) {
break
}
}
}
}
thread.start()
To check if the remote command is still running there is a convinient method in CommandOutput
class boolean isCommandRunning()
which is calculated based on the output results recieved from the remote host.
In the described scenario an endless loop may occur and therefore it is necessary to take care about the shell live timeout:
try {
thread.join(options.maxWait)
} catch (InterruptedException e) {
thread.interrupt()
}
When such interruption occurrs or it is needed to finish command execution unexpectedly for some other reason we invoke
client.cleanupCommand(commandId)
Several remote commands may be executed within one open remote shell one by one. After all commands are executed the shell on the remote host has to be closed to release all used resources
client.deleteShell()
Project's integration tests can be found in the ./src/integrationTest/
folder.
To run the integration tests:
- Create base box using groowin-test-box project. After finishing you will have
windows_2008_r2_virtualbox.box
- Add 'aestasit/2008r2' box using the command
vagrant box add --name aestasit/2008r2 windows_2008_r2_virtualbox.box
- Execute
vagrant up
using the./Vagrantfile
file - execute
gradle integration
command to run integration tests
How to configure the WinRM host to enable communication through the HTTPS protocol