diff --git a/client/src/jaxws/bindings.xml b/client/src/jaxws/bindings.xml index cf7069ad..a7a86d08 100644 --- a/client/src/jaxws/bindings.xml +++ b/client/src/jaxws/bindings.xml @@ -26,5 +26,11 @@ + + + + + diff --git a/client/src/main/java/io/cloudsoft/winrm4j/client/EnumerateCommand.java b/client/src/main/java/io/cloudsoft/winrm4j/client/EnumerateCommand.java new file mode 100644 index 00000000..baab3e1e --- /dev/null +++ b/client/src/main/java/io/cloudsoft/winrm4j/client/EnumerateCommand.java @@ -0,0 +1,235 @@ +package io.cloudsoft.winrm4j.client; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.ws.soap.SOAPFaultException; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import io.cloudsoft.winrm4j.client.enumeration.EnumerateResponse; +import io.cloudsoft.winrm4j.client.enumeration.PullResponse; +import io.cloudsoft.winrm4j.client.wsman.Enumerate; +import io.cloudsoft.winrm4j.client.wsman.Filter; +import io.cloudsoft.winrm4j.client.wsman.Items; +import io.cloudsoft.winrm4j.client.wsman.Locale; +import io.cloudsoft.winrm4j.client.wsman.OptionSetType; +import io.cloudsoft.winrm4j.client.wsman.Pull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import static io.cloudsoft.winrm4j.client.WinRmClient.MAX_ENVELOPER_SIZE; + +public class EnumerateCommand implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(EnumerateCommand.class.getName()); + + /** + * If no output is available before the wsman:OperationTimeout expires, the server MUST return a WSManFault with the Code attribute equal to "2150858793" + * https://msdn.microsoft.com/en-us/library/cc251676.aspx + */ + static final String WSMAN_FAULT_CODE_OPERATION_TIMEOUT_EXPIRED = "2150858793"; + + private final WinRm winrm; + private final String resourceUri; + private final String sessionId; + private final long maxElements; + private final Supplier operationTimeout; + private final Supplier locale; + private final Predicate retryReceiveAfterOperationTimeout; + + private final DocumentBuilder documentBuilder; + + public EnumerateCommand(final WinRm winrm, + final String resourceUri, + final long maxElements, + final Supplier operationTimeout, + final Supplier locale, + final Predicate retryReceiveAfterOperationTimeout) { + this.winrm = winrm; + this.resourceUri = resourceUri; + this.sessionId = "uuid:" + UUID.randomUUID(); + this.maxElements = maxElements; + this.operationTimeout = operationTimeout; + this.locale = locale; + this.retryReceiveAfterOperationTimeout = retryReceiveAfterOperationTimeout; + try { + this.documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new IllegalStateException("Failed to create instance of DocumentBuilder"); + } + } + + public List execute(final String filter, final String dialect) { + final EnumerateResponse enumerateResponse = enumerate(filter, dialect); + final List result = new ArrayList<>(); + collectAndIterateEnumeratedResults(result, new EnumerationPullState( + resourceUri, + maxElements, + enumerateResponse.getEnumerationContext(), + enumerateResponse.getItems(), + enumerateResponse.getEndOfSequence() != null + )); + return result; + } + + private EnumerateResponse enumerate(final String filter, final String dialect) { + while (true) { + try { + final Enumerate enumerate = new Enumerate(); + enumerate.setFilter(new Filter()); + enumerate.getFilter().setValue(filter); + enumerate.getFilter().setDialect(dialect); + enumerate.setMaxElements(maxElements); + return winrm.enumerate( + enumerate, + resourceUri, + sessionId, + MAX_ENVELOPER_SIZE, + operationTimeout.get(), + locale.get(), + new OptionSetType() + ); + } catch (final SOAPFaultException soapFault) { + /** + * If such Exception which has a code 2150858793 the client is expected to again trigger immediately a receive request. + * https://msdn.microsoft.com/en-us/library/cc251676.aspx + */ + assertFaultCode(soapFault, WSMAN_FAULT_CODE_OPERATION_TIMEOUT_EXPIRED, + retryReceiveAfterOperationTimeout); + } + } + } + + private PullResponse pull(final EnumerationPullState state) { + while (true) { + try { + final Pull pull = new Pull(); + pull.setEnumerationContext(state.getEnumerationContext()); + pull.setMaxElements(maxElements); + return winrm.enumeratePull( + pull, + state.getResourceId(), + sessionId, + MAX_ENVELOPER_SIZE, + operationTimeout.get(), + locale.get(), + new OptionSetType() + ); + } catch (final SOAPFaultException soapFault) { + /** + * If such Exception which has a code 2150858793 the client is expected to again trigger immediately a receive request. + * https://msdn.microsoft.com/en-us/library/cc251676.aspx + */ + assertFaultCode(soapFault, WSMAN_FAULT_CODE_OPERATION_TIMEOUT_EXPIRED, + retryReceiveAfterOperationTimeout); + } + } + } + + void collectAndIterateEnumeratedResults(final List result, final EnumerationPullState state) { + + final Document doc = documentBuilder.newDocument(); + final Element root = doc.createElement("results"); + doc.appendChild(root); + + final Items items = state.getItems(); + if (items != null) { + final List elements = items.getAny(); + if (elements != null) { + for (Object element : elements) { + if (element instanceof Node) { + final Node node = doc.importNode((Node) element, true); + root.appendChild(node); + result.add(node); + } else { + LOG.debug("{} unexpected element type {}", this, element.getClass().getCanonicalName()); + } + } + } + } + // There will be additional data available if context is given and the element sequence is not ended. + if (state.getEnumerationContext() != null && !state.isEndOfSequence()) { + final PullResponse next = pull(state); + final boolean endOfSequence = next.getEndOfSequence() != null; + LOG.debug("{} endOfSequence = {}", this, endOfSequence); + collectAndIterateEnumeratedResults(result, new EnumerationPullState( + state.getResourceId(), + state.getMaxElements(), + next.getEnumerationContext(), + next.getItems(), + endOfSequence + )); + } + } + + void assertFaultCode(SOAPFaultException soapFault, String code, Predicate retry) { + try { + NodeList faultDetails = soapFault.getFault().getDetail().getChildNodes(); + for (int i = 0; i < faultDetails.getLength(); i++) { + if (faultDetails.item(i).getLocalName().equals("WSManFault")) { + if (faultDetails.item(i).getAttributes().getNamedItem("Code").getNodeValue().equals(code) + && retry.test(code)) { + LOG.trace("winrm client {} received error 500 response with code {}, response {}", this, code, soapFault); + return; + } else { + throw soapFault; + } + } + } + throw soapFault; + } catch (NullPointerException e) { + LOG.debug("Error reading Fault Code {}", soapFault.getFault()); + throw soapFault; + } + } + + @Override + public void close() throws Exception { + } + + static class EnumerationPullState { + private final String resourceId; + private final long maxElements; + private final String enumerationContext; + private final Items items; + private final boolean endOfSequence; + + public EnumerationPullState(final String resourceId, final long maxElements, final String enumerationContext, final Items items, final boolean endOfSequence) { + this.resourceId = resourceId; + this.maxElements = maxElements; + this.enumerationContext = enumerationContext; + this.items = items; + this.endOfSequence = endOfSequence; + } + + public String getResourceId() { + return resourceId; + } + + public long getMaxElements() { + return maxElements; + } + + public String getEnumerationContext() { + return enumerationContext; + } + + public Items getItems() { + return items; + } + + public boolean isEndOfSequence() { + return endOfSequence; + } + } + +} diff --git a/client/src/main/java/io/cloudsoft/winrm4j/client/WinRmClient.java b/client/src/main/java/io/cloudsoft/winrm4j/client/WinRmClient.java index 36d1c843..c903aeaa 100644 --- a/client/src/main/java/io/cloudsoft/winrm4j/client/WinRmClient.java +++ b/client/src/main/java/io/cloudsoft/winrm4j/client/WinRmClient.java @@ -82,6 +82,7 @@ import io.cloudsoft.winrm4j.client.wsman.OptionSetType; import io.cloudsoft.winrm4j.client.wsman.OptionType; import sun.awt.image.ImageWatched.Link; +import org.w3c.dom.Node; /** * TODO confirm if commands can be called in parallel in one shell (probably not)! @@ -565,6 +566,42 @@ private static String getShellId(ResourceCreated resourceCreated) { throw new IllegalStateException("Shell ID not fount in " + resourceCreated); } + /** + * Executes a WMI query and returns all results as a list. + * + * @param namespace wmi namespace, default may be "root/cimv2/*" + * @param query wmi query, e.g. "Select * From Win32_TimeZone" + * @return list of nodes + */ + public List runWql(String namespace, String query) { + String resourceUri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/" + namespace; + String dialect = "http://schemas.microsoft.com/wbem/wsman/1/WQL"; + return enumerateAndPull(resourceUri, dialect, query); + } + + /** + * Executes, enumerates and returns the result list. + * + * @param resourceUri remote resource uri to filter (must support enumeration) + * @param dialect filter dialect + * @param filter resource filter + * @return list of nodes + */ + public List enumerateAndPull(String resourceUri, String dialect, String filter) { + try (EnumerateCommand command = new EnumerateCommand( + winrm, + resourceUri, + 32000L, + () -> operationTimeout, + () -> locale, + retryReceiveAfterOperationTimeout + )) { + return command.execute(filter, dialect); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + /** * @deprecated since 0.6.0. Use {@link ShellCommand#close()} instead. */ diff --git a/client/src/test/java/io/cloudsoft/winrm4j/client/RetryingProxyHandlerTest.java b/client/src/test/java/io/cloudsoft/winrm4j/client/RetryingProxyHandlerTest.java index 68986d39..1edd1a8c 100644 --- a/client/src/test/java/io/cloudsoft/winrm4j/client/RetryingProxyHandlerTest.java +++ b/client/src/test/java/io/cloudsoft/winrm4j/client/RetryingProxyHandlerTest.java @@ -16,6 +16,10 @@ import javax.xml.ws.WebServiceException; +import io.cloudsoft.winrm4j.client.enumeration.EnumerateResponse; +import io.cloudsoft.winrm4j.client.enumeration.PullResponse; +import io.cloudsoft.winrm4j.client.wsman.Enumerate; +import io.cloudsoft.winrm4j.client.wsman.Pull; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -197,5 +201,19 @@ public ResourceCreated create(Shell shell, String resourceURI, int maxEnvelopeSi calls.add(call); return (ResourceCreated) handler.apply(call); } + + @Override + public EnumerateResponse enumerate(Enumerate enumerate, String resourceURI, String sessionId, int maxEnvelopeSize, String operationTimeout, Locale locale, OptionSetType optionSet) { + RecordedCall call = new RecordedCall("enumerate", Arrays.asList(enumerate, resourceURI, sessionId, maxEnvelopeSize, operationTimeout, locale, optionSet)); + calls.add(call); + return (EnumerateResponse) handler.apply(call); + } + + @Override + public PullResponse enumeratePull(Pull pull, String resourceURI, String sessionId, int maxEnvelopeSize, String operationTimeout, Locale locale, OptionSetType optionSet) { + RecordedCall call = new RecordedCall("enumeratePull", Arrays.asList(pull, resourceURI, sessionId, maxEnvelopeSize, operationTimeout, locale, optionSet)); + calls.add(call); + return (PullResponse) handler.apply(call); + } } } diff --git a/service/src/main/java/io/cloudsoft/winrm4j/service/WinRm.java b/service/src/main/java/io/cloudsoft/winrm4j/service/WinRm.java index 55b965c1..b571a10f 100644 --- a/service/src/main/java/io/cloudsoft/winrm4j/service/WinRm.java +++ b/service/src/main/java/io/cloudsoft/winrm4j/service/WinRm.java @@ -11,6 +11,10 @@ import javax.xml.ws.BindingType; import javax.xml.ws.RequestWrapper; +import io.cloudsoft.winrm4j.service.enumerate.EnumerateRequest; +import io.cloudsoft.winrm4j.service.enumerate.EnumerateResponse; +import io.cloudsoft.winrm4j.service.enumerate.PullRequest; +import io.cloudsoft.winrm4j.service.enumerate.PullResponse; import io.cloudsoft.winrm4j.service.shell.Receive; import io.cloudsoft.winrm4j.service.shell.ReceiveResponse; import io.cloudsoft.winrm4j.service.shell.Shell; @@ -135,6 +139,53 @@ public ResourceCreated create( @WebParam(name = "OptionSet", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) OptionSetType optionSet ) { + + return null; + } + + @WebMethod(operationName = "Enumerate", action = "http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate") + @Action(input = "http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate", output = "http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse") + @WebResult(name = "EnumerateResponse", targetNamespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration", partName = "EnumerateResponse") + @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) + public EnumerateResponse enumerate( + @WebParam(name = "Enumerate", targetNamespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + EnumerateRequest enumerate, + @WebParam(name = "ResourceURI", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + String resourceURI, + @WebParam(name = "SessionId", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + String sessionId, + @WebParam(name = "MaxEnvelopeSize", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + int maxEnvelopeSize, + @WebParam(name = "OperationTimeout", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + String operationTimeout, + @WebParam(name = "Locale", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + Locale locale, + @WebParam(name = "OptionSet", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + OptionSetType optionSet + ) { + return null; + } + + @WebMethod(operationName = "EnumeratePull", action = "http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull") + @Action(input = "http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull", output = "http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse") + @WebResult(name = "PullResponse", targetNamespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration", partName = "PullResponse") + @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) + public PullResponse enumeratePull( + @WebParam(name = "Pull", targetNamespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + PullRequest pull, + @WebParam(name = "ResourceURI", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + String resourceURI, + @WebParam(name = "SessionId", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + String sessionId, + @WebParam(name = "MaxEnvelopeSize", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + int maxEnvelopeSize, + @WebParam(name = "OperationTimeout", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + String operationTimeout, + @WebParam(name = "Locale", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + Locale locale, + @WebParam(name = "OptionSet", targetNamespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", header = true) + OptionSetType optionSet + ) { return null; } diff --git a/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/EnumerateRequest.java b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/EnumerateRequest.java new file mode 100644 index 00000000..c0e56203 --- /dev/null +++ b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/EnumerateRequest.java @@ -0,0 +1,87 @@ +package io.cloudsoft.winrm4j.service.enumerate; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlValue; + +import java.util.ArrayList; +import java.util.List; + +// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/10cfb548-845b-4979-aae3-3f39d7080e17 +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Enumerate", propOrder = { + "maxElements", + "filter", + "any" +}) +public class EnumerateRequest { + + @XmlElement(name = "MaxElements", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + @XmlSchemaType(name = "unsignedLong") + protected Long maxElements; + + @XmlElement(name = "Filter", namespace = "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", required = true) + protected Filter filter; + + @XmlAnyElement(lax = true) + protected List any; + + @XmlAccessorType(XmlAccessType.FIELD) + public static class Filter { + + @XmlAttribute(name = "Dialect") + protected String dialect; + + @XmlValue + private String value; + + public String getDialect() { + return dialect; + } + + public void setDialect(final String dialect) { + this.dialect = dialect; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + } + + public Long getMaxElements() { + return maxElements; + } + + public void setMaxElements(final Long maxElements) { + this.maxElements = maxElements; + } + + public Filter getFilter() { + return filter; + } + + public void setFilter(final Filter filter) { + this.filter = filter; + } + + public List getAny() { + if (any == null) { + any = new ArrayList<>(); + } + return any; + } + + public void setAny(final List any) { + this.any = any; + } + +} diff --git a/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/EnumerateResponse.java b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/EnumerateResponse.java new file mode 100644 index 00000000..db2cb6e6 --- /dev/null +++ b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/EnumerateResponse.java @@ -0,0 +1,49 @@ +package io.cloudsoft.winrm4j.service.enumerate; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/b79bcdd9-125c-49e0-8a4f-bac4ce878592 +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "EnumerateResponse", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration", propOrder = { + "enumerationContext", + "items", + "endOfSequence" +}) +public class EnumerateResponse { + + @XmlElement(name = "EnumerationContext", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + protected String enumerationContext; + + @XmlElement(name = "Items", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + protected Items items; + + @XmlElement(name = "EndOfSequence", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + protected String endOfSequence; + + public String getEnumerationContext() { + return enumerationContext; + } + + public void setEnumerationContext(final String enumerationContext) { + this.enumerationContext = enumerationContext; + } + + public Items getItems() { + return items; + } + + public void setItems(final Items items) { + this.items = items; + } + + public String getEndOfSequence() { + return endOfSequence; + } + + public void setEndOfSequence(final String endOfSequence) { + this.endOfSequence = endOfSequence; + } +} diff --git a/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/Items.java b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/Items.java new file mode 100644 index 00000000..118200b3 --- /dev/null +++ b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/Items.java @@ -0,0 +1,22 @@ +package io.cloudsoft.winrm4j.service.enumerate; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyElement; + +import java.util.List; + +@XmlAccessorType(XmlAccessType.FIELD) +public class Items { + + @XmlAnyElement(lax = true) + protected List value; + + public List getValue() { + return value; + } + + public void setValue(final List value) { + this.value = value; + } +} diff --git a/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/PullRequest.java b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/PullRequest.java new file mode 100644 index 00000000..bfacb866 --- /dev/null +++ b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/PullRequest.java @@ -0,0 +1,60 @@ +package io.cloudsoft.winrm4j.service.enumerate; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +import java.util.ArrayList; +import java.util.List; + +// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/dfe7084a-dea6-4f7f-b35c-cc7d1ad8060d +// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/0fddd40a-b5c4-4a63-a0bf-3ff9966e9e3e +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Pull", propOrder = { + "enumerationContext", + "maxElements", + "any" +}) +public class PullRequest { + + @XmlElement(name = "EnumerationContext", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration", required = true) + protected String enumerationContext; + + @XmlElement(name = "MaxElements", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + @XmlSchemaType(name = "unsignedLong") + protected Long maxElements; + + @XmlAnyElement(lax = true) + protected List any; + + public String getEnumerationContext() { + return enumerationContext; + } + + public void setEnumerationContext(final String enumerationContext) { + this.enumerationContext = enumerationContext; + } + + public Long getMaxElements() { + return maxElements; + } + + public void setMaxElements(final Long maxElements) { + this.maxElements = maxElements; + } + + public List getAny() { + if (any == null) { + any = new ArrayList<>(); + } + return any; + } + + public void setAny(final List any) { + this.any = any; + } + +} diff --git a/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/PullResponse.java b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/PullResponse.java new file mode 100644 index 00000000..9ec2c14b --- /dev/null +++ b/service/src/main/java/io/cloudsoft/winrm4j/service/enumerate/PullResponse.java @@ -0,0 +1,50 @@ +package io.cloudsoft.winrm4j.service.enumerate; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/939e283a-5518-4e43-9d9f-4f0b1a199815 +// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/8923a1bb-ea8b-49cb-8495-5f2612e7a0f9 +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "PullResponse", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration", propOrder = { + "enumerationContext", + "items", + "endOfSequence" +}) +public class PullResponse { + + @XmlElement(name = "EnumerationContext", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + protected String enumerationContext; + + @XmlElement(name = "Items", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + protected Items items; + + @XmlElement(name = "EndOfSequence", namespace = "http://schemas.xmlsoap.org/ws/2004/09/enumeration") + protected String endOfSequence; + + public String getEnumerationContext() { + return enumerationContext; + } + + public void setEnumerationContext(final String enumerationContext) { + this.enumerationContext = enumerationContext; + } + + public Items getItems() { + return items; + } + + public void setItems(final Items items) { + this.items = items; + } + + public String getEndOfSequence() { + return endOfSequence; + } + + public void setEndOfSequence(final String endOfSequence) { + this.endOfSequence = endOfSequence; + } +} diff --git a/winrm4j/src/main/java/io/cloudsoft/winrm4j/winrm/WinRmTool.java b/winrm4j/src/main/java/io/cloudsoft/winrm4j/winrm/WinRmTool.java index 2f3cead9..6ba40d44 100644 --- a/winrm4j/src/main/java/io/cloudsoft/winrm4j/winrm/WinRmTool.java +++ b/winrm4j/src/main/java/io/cloudsoft/winrm4j/winrm/WinRmTool.java @@ -332,13 +332,9 @@ public WinRmToolResponse executeCommand(String command, List args) { return executeCommand(command, args, DEFAULT_SKIP_COMMAND_SHELL, null, null); } - public WinRmToolResponse executeCommand(String command, Writer out, Writer err) { - return executeCommand(command, null, DEFAULT_SKIP_COMMAND_SHELL, out, err); - } - - public WinRmToolResponse executeCommand(String command, List args, Boolean skipCommandShell, Writer out, Writer err) { - if (out==null) out = new StringWriter(); - if (err==null) err = new StringWriter(); + public WinRmClient buildClient(Writer out, Writer err) { + WinRmClient.checkNotNull(out, "Out Writer"); + WinRmClient.checkNotNull(err, "Err Writer"); WinRmClientBuilder builder = WinRmClient.builder(address); builder.authenticationScheme(authenticationScheme); if (operationTimeout != null) { @@ -364,13 +360,13 @@ public WinRmToolResponse executeCommand(String command, List args, Boole builder.allowChunking(allowChunking); } if (hostnameVerifier != null) { - builder.hostnameVerifier(hostnameVerifier); + builder.hostnameVerifier(hostnameVerifier); } if (sslSocketFactory != null) { - builder.sslSocketFactory(sslSocketFactory); + builder.sslSocketFactory(sslSocketFactory); } if (sslContext != null) { - builder.sslContext(sslContext); + builder.sslContext(sslContext); } if (workingDirectory != null) { builder.workingDirectory(workingDirectory); @@ -389,9 +385,20 @@ public WinRmToolResponse executeCommand(String command, List args, Boole } builder.payloadEncryptionMode(payloadEncryptionMode); + return builder.build(); + } + + public WinRmToolResponse executeCommand(String command, Writer out, Writer err) { + return executeCommand(command, null, DEFAULT_SKIP_COMMAND_SHELL, out, err); + } + + public WinRmToolResponse executeCommand(String command, List args, Boolean skipCommandShell, Writer out, Writer err) { + if (out==null) out = new StringWriter(); + if (err==null) err = new StringWriter(); + WinRmToolResponse winRmToolResponse; - try(WinRmClient client = builder.build()) { + try(WinRmClient client = buildClient(out, err)) { try (ShellCommand shell = client.createShell()) { int code = shell.execute(command, args, skipCommandShell, out, err); winRmToolResponse = new WinRmToolResponse(out.toString(), err.toString(), code);