go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/powershell.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package resources
     5  
     6  import (
     7  	"bytes"
     8  	"io"
     9  	"sync"
    10  
    11  	"github.com/rs/zerolog/log"
    12  	"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
    13  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    14  	"go.mondoo.com/cnquery/providers/os/resources/powershell"
    15  	"golang.org/x/net/html/charset"
    16  	"golang.org/x/text/transform"
    17  )
    18  
    19  type mqlPowershellInternal struct {
    20  	lock       sync.Mutex
    21  	executed   bool
    22  	executeErr error
    23  }
    24  
    25  // TODO: consider sharing more code with command resource
    26  func (c *mqlPowershell) id() (string, error) {
    27  	return c.Script.Data, nil
    28  }
    29  
    30  func (c *mqlPowershell) execute() error {
    31  	c.lock.Lock()
    32  	defer c.lock.Unlock()
    33  
    34  	if c.executed {
    35  		return c.executeErr
    36  	}
    37  	c.executed = true
    38  
    39  	conn := c.MqlRuntime.Connection.(shared.Connection)
    40  	cmd := c.Script.Data
    41  
    42  	// encode the powershell command
    43  	encodedCmd := powershell.Encode(cmd)
    44  	x, err := conn.RunCommand(encodedCmd)
    45  	c.executeErr = err
    46  	if err != nil {
    47  		c.Exitcode = plugin.TValue[int64]{Error: err, State: plugin.StateIsSet}
    48  		c.Stdout = plugin.TValue[string]{Error: err, State: plugin.StateIsSet}
    49  		c.Stderr = plugin.TValue[string]{Error: err, State: plugin.StateIsSet}
    50  		return err
    51  	}
    52  
    53  	c.Exitcode = plugin.TValue[int64]{Data: int64(x.ExitStatus), State: plugin.StateIsSet}
    54  
    55  	stdout, err := io.ReadAll(x.Stdout)
    56  	if err != nil {
    57  		c.Stdout = plugin.TValue[string]{Error: err, State: plugin.StateIsSet}
    58  	} else {
    59  		out, err := convertToUtf8Encoding(stdout)
    60  		c.Stdout = plugin.TValue[string]{Data: out, Error: err, State: plugin.StateIsSet}
    61  	}
    62  
    63  	stderr, err := io.ReadAll(x.Stderr)
    64  	if err != nil {
    65  		c.Stdout = plugin.TValue[string]{Error: err, State: plugin.StateIsSet}
    66  	} else {
    67  		serr, err := convertToUtf8Encoding(stderr)
    68  		c.Stderr = plugin.TValue[string]{Data: string(serr), Error: err, State: plugin.StateIsSet}
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  func convertToUtf8Encoding(out []byte) (string, error) {
    75  	enc, name, _ := charset.DetermineEncoding(out, "")
    76  	log.Trace().Str("encoding", name).Msg("check powershell results charset")
    77  	r := transform.NewReader(bytes.NewReader(out), enc.NewDecoder())
    78  	utf8out, err := io.ReadAll(r)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  	return string(utf8out), nil
    83  }
    84  
    85  func (c *mqlPowershell) stdout() (string, error) {
    86  	return "", c.execute()
    87  }
    88  
    89  func (c *mqlPowershell) stderr() (string, error) {
    90  	return "", c.execute()
    91  }
    92  
    93  func (c *mqlPowershell) exitcode() (int64, error) {
    94  	return 0, c.execute()
    95  }