Skip to content

Commit

Permalink
✨ Add windows.optionalfeatures resource
Browse files Browse the repository at this point in the history
Related-to #3705

Signed-off-by: Christian Zunker <[email protected]>
  • Loading branch information
czunker committed May 29, 2024
1 parent dc5835c commit 81dc479
Show file tree
Hide file tree
Showing 9 changed files with 1,119 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,4 @@ vulnerabilityassessmentsettings
vulnmgmt
wil
xssmatchstatement
optionalfeature
18 changes: 18 additions & 0 deletions providers/os/resources/os.lr
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,9 @@ windows {

// Information about Windows Server roles, role services, and features that are available for installation and installed on a specified server.
features() []windows.feature

// Information about optional features in a Windows image.
optionalfeatures() []windows.optionalfeature
}

// Windows hotfix resource
Expand Down Expand Up @@ -1423,6 +1426,21 @@ windows.feature {
installState int
}

// Windows optional feature resource
windows.optionalfeature @defaults("name enabled") {
init(name string)
// Command ID of optional feature
name string
// Feature name
displayName string
// Feature description
description string
// Whether the feature is enabled
enabled bool
// Feature installation state
state int
}

// Windows Firewall resource
windows.firewall {
// Global firewall settings
Expand Down
136 changes: 136 additions & 0 deletions providers/os/resources/os.lr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions providers/os/resources/os.lr.manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,8 @@ resources:
computerInfo: {}
features: {}
hotfixes: {}
optionalfeatures:
min_mondoo_version: latest
min_mondoo_version: 5.15.0
snippets:
- query: windows.computerInfo['WindowsInstallationType'] == 'Server Core'
Expand Down Expand Up @@ -1158,6 +1160,14 @@ resources:
installedBy: {}
installedOn: {}
min_mondoo_version: 5.15.0
windows.optionalfeature:
fields:
description: {}
displayName: {}
enabled: {}
name: {}
state: {}
min_mondoo_version: latest
windows.security:
fields:
products: {}
Expand Down
77 changes: 77 additions & 0 deletions providers/os/resources/windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,80 @@ func (w *mqlWindows) features() ([]interface{}, error) {

return mqlFeatures, nil
}

func (wh *mqlWindowsOptionalfeature) id() (string, error) {
return wh.Name.Data, nil
}

func initmqlWindowsOptionalfeature(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) {

Check failure on line 190 in providers/os/resources/windows.go

View workflow job for this annotation

GitHub Actions / golangci-lint

func `initmqlWindowsOptionalfeature` is unused (unused)
if len(args) > 1 {
return args, nil, nil
}

nameRaw := args["name"]
if nameRaw == nil {
return args, nil, nil
}

name, ok := nameRaw.Value.(string)
if !ok {
return args, nil, nil
}

obj, err := NewResource(runtime, "windows", nil)
if err != nil {
return nil, nil, err
}
winResource := obj.(*mqlWindows)

features := winResource.GetOptionalfeatures()
if features.Error != nil {
return nil, nil, features.Error
}

for i := range features.Data {
hf := features.Data[i].(*mqlWindowsOptionalfeature)
if hf.Name.Data == name {
return nil, hf, nil
}
}

// if the feature cannot be found we return an error
return nil, nil, errors.New("could not find feature " + name)
}

func (w *mqlWindows) optionalfeatures() ([]interface{}, error) {
conn := w.MqlRuntime.Connection.(shared.Connection)

// query features
encodedCmd := powershell.Encode(windows.QUERY_OPTIONAL_FEATURES)
executedCmd, err := conn.RunCommand(encodedCmd)
if err != nil {
return nil, err
}

features, err := windows.ParseWindowsOptionalFeatures(executedCmd.Stdout)
if err != nil {
return nil, err
}

// convert features to MQL resource
mqlFeatures := make([]interface{}, len(features))
for i, feature := range features {

mqlFeature, err := CreateResource(w.MqlRuntime, "windows.optionalfeature", map[string]*llx.RawData{
"name": llx.StringData(feature.Name),
"displayName": llx.StringData(feature.DisplayName),
"description": llx.StringData(feature.Description),
"enabled": llx.BoolData(feature.Enabled),
"state": llx.IntData(feature.State),
})
if err != nil {
return nil, err
}

mqlFeatures[i] = mqlFeature
}

return mqlFeatures, nil
}
45 changes: 45 additions & 0 deletions providers/os/resources/windows/optionalfeatures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package windows

import (
"encoding/json"
"io"
)

const QUERY_OPTIONAL_FEATURES = "Get-WindowsOptionalFeature -Online -FeatureName * | Select-Object -Property FeatureName,DisplayName,Description,State | ConvertTo-Json"

type WindowsOptionalFeature struct {
Name string `json:"FeatureName"`
DisplayName string `json:"DisplayName"`
Description string `json:"Description"`
Enabled bool `json:"Enabled"`
State int64 `json:"State"`
}

func ParseWindowsOptionalFeatures(input io.Reader) ([]WindowsOptionalFeature, error) {
data, err := io.ReadAll(input)
if err != nil {
return nil, err
}

// for empty result set do not get the '{}', therefore lets abort here
if len(data) == 0 {
return []WindowsOptionalFeature{}, nil
}

var winFeatures []WindowsOptionalFeature
err = json.Unmarshal(data, &winFeatures)
if err != nil {
return nil, err
}

for i := range winFeatures {
if winFeatures[i].State == 2 {
winFeatures[i].Enabled = true
}
}

return winFeatures, nil
}
Loading

0 comments on commit 81dc479

Please sign in to comment.