125 lines
2.9 KiB
Go
125 lines
2.9 KiB
Go
package winrm
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/ChrisTrenkamp/goxpath"
|
|
"github.com/ChrisTrenkamp/goxpath/tree"
|
|
"github.com/ChrisTrenkamp/goxpath/tree/xmltree"
|
|
"github.com/masterzen/winrm/soap"
|
|
)
|
|
|
|
func first(node tree.Node, xpath string) (string, error) {
|
|
nodes, err := xPath(node, xpath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(nodes) < 1 {
|
|
return "", err
|
|
}
|
|
return nodes[0].ResValue(), nil
|
|
}
|
|
|
|
func any(node tree.Node, xpath string) (bool, error) {
|
|
nodes, err := xPath(node, xpath)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if len(nodes) > 0 {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func xPath(node tree.Node, xpath string) (tree.NodeSet, error) {
|
|
xpExec := goxpath.MustParse(xpath)
|
|
nodes, err := xpExec.ExecNode(node, soap.GetAllXPathNamespaces())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return nodes, nil
|
|
}
|
|
|
|
func ParseOpenShellResponse(response string) (string, error) {
|
|
doc, err := xmltree.ParseXML(strings.NewReader(response))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return first(doc, "//w:Selector[@Name='ShellId']")
|
|
}
|
|
|
|
func ParseExecuteCommandResponse(response string) (string, error) {
|
|
doc, err := xmltree.ParseXML(strings.NewReader(response))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return first(doc, "//rsp:CommandId")
|
|
}
|
|
|
|
func ParseSlurpOutputErrResponse(response string, stdout, stderr io.Writer) (bool, int, error) {
|
|
var (
|
|
finished bool
|
|
exitCode int
|
|
)
|
|
|
|
doc, err := xmltree.ParseXML(strings.NewReader(response))
|
|
|
|
stdouts, _ := xPath(doc, "//rsp:Stream[@Name='stdout']")
|
|
for _, node := range stdouts {
|
|
content, _ := base64.StdEncoding.DecodeString(node.ResValue())
|
|
stdout.Write(content)
|
|
}
|
|
stderrs, _ := xPath(doc, "//rsp:Stream[@Name='stderr']")
|
|
for _, node := range stderrs {
|
|
content, _ := base64.StdEncoding.DecodeString(node.ResValue())
|
|
stderr.Write(content)
|
|
}
|
|
|
|
ended, _ := any(doc, "//*[@State='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done']")
|
|
|
|
if ended {
|
|
finished = ended
|
|
if exitBool, _ := any(doc, "//rsp:ExitCode"); exitBool {
|
|
exit, _ := first(doc, "//rsp:ExitCode")
|
|
exitCode, _ = strconv.Atoi(exit)
|
|
}
|
|
} else {
|
|
finished = false
|
|
}
|
|
|
|
return finished, exitCode, err
|
|
}
|
|
|
|
func ParseSlurpOutputResponse(response string, stream io.Writer, streamType string) (bool, int, error) {
|
|
var (
|
|
finished bool
|
|
exitCode int
|
|
)
|
|
|
|
doc, err := xmltree.ParseXML(strings.NewReader(response))
|
|
|
|
nodes, _ := xPath(doc, fmt.Sprintf("//rsp:Stream[@Name='%s']", streamType))
|
|
for _, node := range nodes {
|
|
content, _ := base64.StdEncoding.DecodeString(node.ResValue())
|
|
stream.Write(content)
|
|
}
|
|
|
|
ended, _ := any(doc, "//*[@State='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done']")
|
|
|
|
if ended {
|
|
finished = ended
|
|
if exitBool, _ := any(doc, "//rsp:ExitCode"); exitBool {
|
|
exit, _ := first(doc, "//rsp:ExitCode")
|
|
exitCode, _ = strconv.Atoi(exit)
|
|
}
|
|
} else {
|
|
finished = false
|
|
}
|
|
|
|
return finished, exitCode, err
|
|
}
|