From 81dc4790a863c39dd3efb2ac5209e13d45de93b0 Mon Sep 17 00:00:00 2001 From: Christian Zunker Date: Wed, 29 May 2024 10:27:29 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20windows.optionalfeatures=20re?= =?UTF-8?q?source?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related-to #3705 Signed-off-by: Christian Zunker --- .github/actions/spelling/expect.txt | 1 + providers/os/resources/os.lr | 18 + providers/os/resources/os.lr.go | 136 +++ providers/os/resources/os.lr.manifest.yaml | 10 + providers/os/resources/windows.go | 77 ++ .../os/resources/windows/optionalfeatures.go | 45 + .../windows/optionalfeatures_test.go | 26 + .../windows/testdata/optionalfeatures.json | 806 ++++++++++++++++++ .../windows/testdata/optionalfeatures2.json | Bin 0 -> 127513 bytes 9 files changed, 1119 insertions(+) create mode 100644 providers/os/resources/windows/optionalfeatures.go create mode 100644 providers/os/resources/windows/optionalfeatures_test.go create mode 100644 providers/os/resources/windows/testdata/optionalfeatures.json create mode 100644 providers/os/resources/windows/testdata/optionalfeatures2.json diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index b9377c89f0..0d1ae43ecf 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -91,3 +91,4 @@ vulnerabilityassessmentsettings vulnmgmt wil xssmatchstatement +optionalfeature diff --git a/providers/os/resources/os.lr b/providers/os/resources/os.lr index 62b366f6c0..9edaaf175e 100644 --- a/providers/os/resources/os.lr +++ b/providers/os/resources/os.lr @@ -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 @@ -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 diff --git a/providers/os/resources/os.lr.go b/providers/os/resources/os.lr.go index 4f3e4ed38e..a8f8050be8 100644 --- a/providers/os/resources/os.lr.go +++ b/providers/os/resources/os.lr.go @@ -434,6 +434,10 @@ func init() { Init: initWindowsFeature, Create: createWindowsFeature, }, + "windows.optionalfeature": { + // to override args, implement: initWindowsOptionalfeature(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createWindowsOptionalfeature, + }, "windows.firewall": { // to override args, implement: initWindowsFirewall(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createWindowsFirewall, @@ -1974,6 +1978,9 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "windows.features": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlWindows).GetFeatures()).ToDataRes(types.Array(types.Resource("windows.feature"))) }, + "windows.optionalfeatures": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWindows).GetOptionalfeatures()).ToDataRes(types.Array(types.Resource("windows.optionalfeature"))) + }, "windows.hotfix.hotfixId": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlWindowsHotfix).GetHotfixId()).ToDataRes(types.String) }, @@ -2007,6 +2014,21 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "windows.feature.installState": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlWindowsFeature).GetInstallState()).ToDataRes(types.Int) }, + "windows.optionalfeature.name": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWindowsOptionalfeature).GetName()).ToDataRes(types.String) + }, + "windows.optionalfeature.displayName": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWindowsOptionalfeature).GetDisplayName()).ToDataRes(types.String) + }, + "windows.optionalfeature.description": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWindowsOptionalfeature).GetDescription()).ToDataRes(types.String) + }, + "windows.optionalfeature.enabled": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWindowsOptionalfeature).GetEnabled()).ToDataRes(types.Bool) + }, + "windows.optionalfeature.state": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWindowsOptionalfeature).GetState()).ToDataRes(types.Int) + }, "windows.firewall.settings": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlWindowsFirewall).GetSettings()).ToDataRes(types.Dict) }, @@ -4530,6 +4552,10 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlWindows).Features, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) return }, + "windows.optionalfeatures": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWindows).Optionalfeatures, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, "windows.hotfix.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlWindowsHotfix).__id, ok = v.Value.(string) return @@ -4582,6 +4608,30 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlWindowsFeature).InstallState, ok = plugin.RawToTValue[int64](v.Value, v.Error) return }, + "windows.optionalfeature.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWindowsOptionalfeature).__id, ok = v.Value.(string) + return + }, + "windows.optionalfeature.name": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWindowsOptionalfeature).Name, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "windows.optionalfeature.displayName": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWindowsOptionalfeature).DisplayName, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "windows.optionalfeature.description": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWindowsOptionalfeature).Description, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "windows.optionalfeature.enabled": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWindowsOptionalfeature).Enabled, ok = plugin.RawToTValue[bool](v.Value, v.Error) + return + }, + "windows.optionalfeature.state": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWindowsOptionalfeature).State, ok = plugin.RawToTValue[int64](v.Value, v.Error) + return + }, "windows.firewall.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlWindowsFirewall).__id, ok = v.Value.(string) return @@ -12982,6 +13032,7 @@ type mqlWindows struct { ComputerInfo plugin.TValue[interface{}] Hotfixes plugin.TValue[[]interface{}] Features plugin.TValue[[]interface{}] + Optionalfeatures plugin.TValue[[]interface{}] } // createWindows creates a new instance of this resource @@ -13054,6 +13105,22 @@ func (c *mqlWindows) GetFeatures() *plugin.TValue[[]interface{}] { }) } +func (c *mqlWindows) GetOptionalfeatures() *plugin.TValue[[]interface{}] { + return plugin.GetOrCompute[[]interface{}](&c.Optionalfeatures, func() ([]interface{}, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("windows", c.__id, "optionalfeatures") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.([]interface{}), nil + } + } + + return c.optionalfeatures() + }) +} + // mqlWindowsHotfix for the windows.hotfix resource type mqlWindowsHotfix struct { MqlRuntime *plugin.Runtime @@ -13197,6 +13264,75 @@ func (c *mqlWindowsFeature) GetInstallState() *plugin.TValue[int64] { return &c.InstallState } +// mqlWindowsOptionalfeature for the windows.optionalfeature resource +type mqlWindowsOptionalfeature struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlWindowsOptionalfeatureInternal it will be used here + Name plugin.TValue[string] + DisplayName plugin.TValue[string] + Description plugin.TValue[string] + Enabled plugin.TValue[bool] + State plugin.TValue[int64] +} + +// createWindowsOptionalfeature creates a new instance of this resource +func createWindowsOptionalfeature(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlWindowsOptionalfeature{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + if res.__id == "" { + res.__id, err = res.id() + if err != nil { + return nil, err + } + } + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("windows.optionalfeature", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlWindowsOptionalfeature) MqlName() string { + return "windows.optionalfeature" +} + +func (c *mqlWindowsOptionalfeature) MqlID() string { + return c.__id +} + +func (c *mqlWindowsOptionalfeature) GetName() *plugin.TValue[string] { + return &c.Name +} + +func (c *mqlWindowsOptionalfeature) GetDisplayName() *plugin.TValue[string] { + return &c.DisplayName +} + +func (c *mqlWindowsOptionalfeature) GetDescription() *plugin.TValue[string] { + return &c.Description +} + +func (c *mqlWindowsOptionalfeature) GetEnabled() *plugin.TValue[bool] { + return &c.Enabled +} + +func (c *mqlWindowsOptionalfeature) GetState() *plugin.TValue[int64] { + return &c.State +} + // mqlWindowsFirewall for the windows.firewall resource type mqlWindowsFirewall struct { MqlRuntime *plugin.Runtime diff --git a/providers/os/resources/os.lr.manifest.yaml b/providers/os/resources/os.lr.manifest.yaml index 668235fe6a..b6da8d52fd 100644 --- a/providers/os/resources/os.lr.manifest.yaml +++ b/providers/os/resources/os.lr.manifest.yaml @@ -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' @@ -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: {} diff --git a/providers/os/resources/windows.go b/providers/os/resources/windows.go index c8f63da14a..4af87c4833 100644 --- a/providers/os/resources/windows.go +++ b/providers/os/resources/windows.go @@ -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) { + 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 +} diff --git a/providers/os/resources/windows/optionalfeatures.go b/providers/os/resources/windows/optionalfeatures.go new file mode 100644 index 0000000000..580cb41cfa --- /dev/null +++ b/providers/os/resources/windows/optionalfeatures.go @@ -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 +} diff --git a/providers/os/resources/windows/optionalfeatures_test.go b/providers/os/resources/windows/optionalfeatures_test.go new file mode 100644 index 0000000000..ac0e95842d --- /dev/null +++ b/providers/os/resources/windows/optionalfeatures_test.go @@ -0,0 +1,26 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package windows + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWindowsOptionalFeatures(t *testing.T) { + r, err := os.Open("./testdata/optionalfeatures.json") + require.NoError(t, err) + + items, err := ParseWindowsOptionalFeatures(r) + assert.Nil(t, err) + assert.Equal(t, 134, len(items)) + assert.Equal(t, "MicrosoftWindowsPowerShellV2", items[9].Name) + assert.Equal(t, "Windows PowerShell 2.0 Engine", items[9].DisplayName) + assert.True(t, items[9].Enabled) + assert.Equal(t, int64(2), items[9].State) + assert.Equal(t, "Adds or Removes Windows PowerShell 2.0 Engine", items[9].Description) +} diff --git a/providers/os/resources/windows/testdata/optionalfeatures.json b/providers/os/resources/windows/testdata/optionalfeatures.json new file mode 100644 index 0000000000..3f440ed181 --- /dev/null +++ b/providers/os/resources/windows/testdata/optionalfeatures.json @@ -0,0 +1,806 @@ +[ + { + "FeatureName": "Windows-Defender-Default-Definitions", + "DisplayName": "", + "Description": "", + "State": 0 + }, + { + "FeatureName": "Printing-PrintToPDFServices-Features", + "DisplayName": "Microsoft Print to PDF", + "Description": "Provides binaries on the system for creating the Microsoft Print to PDF Print Queue", + "State": 2 + }, + { + "FeatureName": "Printing-XPSServices-Features", + "DisplayName": "Microsoft XPS Document Writer", + "Description": "Provides binaries on the system for creating the XPS Document Writer Print Queue", + "State": 0 + }, + { + "FeatureName": "TelnetClient", + "DisplayName": "Telnet Client", + "Description": "Allows you to connect to other computers remotely.", + "State": 0 + }, + { + "FeatureName": "LegacyComponents", + "DisplayName": "Legacy Components", + "Description": "Controls legacy components in Windows.", + "State": 0 + }, + { + "FeatureName": "DirectPlay", + "DisplayName": "DirectPlay", + "Description": "Enables the installation of DirectPlay component.", + "State": 0 + }, + { + "FeatureName": "MSRDC-Infrastructure", + "DisplayName": "Remote Differential Compression API Support", + "Description": "Installs Remote Differential Compression (RDC) support for use in third-party applications.", + "State": 2 + }, + { + "FeatureName": "Windows-Identity-Foundation", + "DisplayName": "Windows Identity Foundation 3.5", + "Description": "Windows Identity Foundation (WIF) 3.5 is a set of .NET Framework classes that can be used for implementing claims-based identity in your .NET 3.5 and 4.0 applications. WIF 3.5 has been superseded by WIF classes that are provided as part of .NET 4.5. It is recommended that you use .NET 4.5 for supporting claims-based identity in your applications.", + "State": 0 + }, + { + "FeatureName": "MicrosoftWindowsPowerShellV2Root", + "DisplayName": "Windows PowerShell 2.0", + "Description": "Adds or Removes Windows PowerShell 2.0", + "State": 2 + }, + { + "FeatureName": "MicrosoftWindowsPowerShellV2", + "DisplayName": "Windows PowerShell 2.0 Engine", + "Description": "Adds or Removes Windows PowerShell 2.0 Engine", + "State": 2 + }, + { + "FeatureName": "SimpleTCP", + "DisplayName": "Simple TCPIP services (i.e. echo, daytime etc)", + "Description": "Install Simple TCPIP services", + "State": 0 + }, + { + "FeatureName": "SMB1Protocol-Deprecation", + "DisplayName": "SMB 1.0/CIFS Automatic Removal", + "Description": "Automatically removes support for the legacy SMB 1.0/CIFS protocol when such support isn\u0027t actively needed during normal system usage.", + "State": 0 + }, + { + "FeatureName": "WCF-HTTP-Activation", + "DisplayName": "Windows Communication Foundation HTTP Activation", + "Description": "Windows Communication Foundation HTTP Activation", + "State": 0 + }, + { + "FeatureName": "WCF-NonHTTP-Activation", + "DisplayName": "Windows Communication Foundation Non-HTTP Activation", + "Description": "Windows Communication Foundation Non-HTTP Activation", + "State": 0 + }, + { + "FeatureName": "WCF-Services45", + "DisplayName": "WCF Services", + "Description": "WCF Services", + "State": 2 + }, + { + "FeatureName": "WCF-HTTP-Activation45", + "DisplayName": "HTTP Activation", + "Description": "HTTP Activation", + "State": 0 + }, + { + "FeatureName": "WCF-TCP-Activation45", + "DisplayName": "TCP Activation", + "Description": "TCP Activation", + "State": 0 + }, + { + "FeatureName": "WCF-Pipe-Activation45", + "DisplayName": "Named Pipe Activation", + "Description": "Named Pipe Activation", + "State": 0 + }, + { + "FeatureName": "WCF-MSMQ-Activation45", + "DisplayName": "Message Queuing (MSMQ) Activation", + "Description": "Message Queuing (MSMQ) Activation", + "State": 0 + }, + { + "FeatureName": "WCF-TCP-PortSharing45", + "DisplayName": "TCP Port Sharing", + "Description": "TCP Port Sharing", + "State": 2 + }, + { + "FeatureName": "MediaPlayback", + "DisplayName": "Media Features", + "Description": "Controls media features such as Windows Media Player.", + "State": 2 + }, + { + "FeatureName": "WindowsMediaPlayer", + "DisplayName": "Windows Media Player Legacy (App)", + "Description": "Windows Media Player Legacy (App)", + "State": 2 + }, + { + "FeatureName": "HostGuardian", + "DisplayName": "Guarded Host", + "Description": "Enables the device to create and run Shielded Virtual Machine using remote attestation.", + "State": 0 + }, + { + "FeatureName": "ServicesForNFS-ClientOnly", + "DisplayName": "Services for NFS", + "Description": "Allows you to access files using the Network File System (NFS) protocol.", + "State": 0 + }, + { + "FeatureName": "ClientForNFS-Infrastructure", + "DisplayName": "Client for NFS", + "Description": "Enables this computer to gain access to files on UNIX-based computers", + "State": 0 + }, + { + "FeatureName": "NFS-Administration", + "DisplayName": "Administrative Tools", + "Description": "Tools for managing Services for NFS on local and remote computers", + "State": 0 + }, + { + "FeatureName": "SmbDirect", + "DisplayName": "SMB Direct", + "Description": "Remote Direct Memory Access (RDMA) support for the SMB 3.x file sharing protocol", + "State": 2 + }, + { + "FeatureName": "MultiPoint-Connector", + "DisplayName": "MultiPoint Connector", + "Description": "Allows your computer to be monitored and managed by the MultiPoint Manager and MultiPoint Dashboard apps.", + "State": 0 + }, + { + "FeatureName": "MultiPoint-Connector-Services", + "DisplayName": "MultiPoint Connector Services", + "Description": "Allows your computer to be monitored and managed by the MultiPoint Manager and MultiPoint Dashboard apps.", + "State": 0 + }, + { + "FeatureName": "MultiPoint-Tools", + "DisplayName": "MultiPoint Manager and MultiPoint Dashboard", + "Description": "GUI tools for managing MultiPoint.", + "State": 0 + }, + { + "FeatureName": "TFTP", + "DisplayName": "TFTP Client", + "Description": "Transfer files using the Trivial File Transfer Protocol", + "State": 0 + }, + { + "FeatureName": "NetFx3", + "DisplayName": ".NET Framework 3.5 (includes .NET 2.0 and 3.0)", + "Description": ".NET Framework 3.5 (includes .NET 2.0 and 3.0)", + "State": 6 + }, + { + "FeatureName": "IIS-WebServerRole", + "DisplayName": "Internet Information Services", + "Description": "Internet Information Services provides support for Web and FTP servers, along with support for ASP.NET web sites, dynamic content such as Classic ASP and CGI, and local and remote management.", + "State": 0 + }, + { + "FeatureName": "IIS-WebServer", + "DisplayName": "World Wide Web Services", + "Description": "Installs the IIS 10.0 World Wide Web Services. Provides support for HTML web sites and optional support for ASP.NET, Classic ASP, and web server extensions.", + "State": 0 + }, + { + "FeatureName": "IIS-CommonHttpFeatures", + "DisplayName": "Common HTTP Features", + "Description": "Installs support for Web server content such as HTML and image files.", + "State": 0 + }, + { + "FeatureName": "IIS-HttpErrors", + "DisplayName": "HTTP Errors", + "Description": "Allows you to customize the error messages returned to clients", + "State": 0 + }, + { + "FeatureName": "IIS-HttpRedirect", + "DisplayName": "HTTP Redirection", + "Description": "Redirect client requests to a specific destination", + "State": 0 + }, + { + "FeatureName": "IIS-ApplicationDevelopment", + "DisplayName": "Application Development Features", + "Description": "Install Web server application development features", + "State": 0 + }, + { + "FeatureName": "IIS-Security", + "DisplayName": "Security", + "Description": "Enable additional security features to secure servers, sites, applications, vdirs, and files", + "State": 0 + }, + { + "FeatureName": "IIS-RequestFiltering", + "DisplayName": "Request Filtering", + "Description": "Configure rules to block selected client requests.", + "State": 0 + }, + { + "FeatureName": "IIS-NetFxExtensibility", + "DisplayName": ".NET Extensibility 3.5", + "Description": "Enable your Web server to host .NET Framework 3.5 applications", + "State": 0 + }, + { + "FeatureName": "IIS-NetFxExtensibility45", + "DisplayName": ".NET Extensibility 4.8", + "Description": "Enable your Web server to host .NET Framework v4.8 applications", + "State": 0 + }, + { + "FeatureName": "IIS-HealthAndDiagnostics", + "DisplayName": "Health and Diagnostics", + "Description": "Enables you to monitor and manage server, site, and application health", + "State": 0 + }, + { + "FeatureName": "IIS-HttpLogging", + "DisplayName": "HTTP Logging", + "Description": "Enables logging of Web site activity for this server", + "State": 0 + }, + { + "FeatureName": "IIS-LoggingLibraries", + "DisplayName": "Logging Tools", + "Description": "Install IIS 10.0 logging tools and scripts", + "State": 0 + }, + { + "FeatureName": "IIS-RequestMonitor", + "DisplayName": "Request Monitor", + "Description": "Monitor server, site, and application health", + "State": 0 + }, + { + "FeatureName": "IIS-HttpTracing", + "DisplayName": "Tracing", + "Description": "Enable tracing for ASP.NET applications and failed requests", + "State": 0 + }, + { + "FeatureName": "IIS-URLAuthorization", + "DisplayName": "URL Authorization", + "Description": "Authorize client access to the URLs that comprise a Web application.", + "State": 0 + }, + { + "FeatureName": "IIS-IPSecurity", + "DisplayName": "IP Security", + "Description": "Allow or deny content access based on IP address or domain name.", + "State": 0 + }, + { + "FeatureName": "IIS-Performance", + "DisplayName": "Performance Features", + "Description": "Install performance features", + "State": 0 + }, + { + "FeatureName": "IIS-HttpCompressionDynamic", + "DisplayName": "Dynamic Content Compression", + "Description": "Compress dynamic content before returning it to client", + "State": 0 + }, + { + "FeatureName": "IIS-WebServerManagementTools", + "DisplayName": "Web Management Tools", + "Description": "Install Web management console and tools", + "State": 0 + }, + { + "FeatureName": "IIS-ManagementScriptingTools", + "DisplayName": "IIS Management Scripts and Tools", + "Description": "Manage a local Web server with IIS configuration scripts", + "State": 0 + }, + { + "FeatureName": "IIS-IIS6ManagementCompatibility", + "DisplayName": "IIS 6 Management Compatibility", + "Description": "Allows you to use existing IIS 6.0 APIs and scripts to manage this IIS 10.0 web server", + "State": 0 + }, + { + "FeatureName": "IIS-Metabase", + "DisplayName": "IIS Metabase and IIS 6 configuration compatibility", + "Description": "Install IIS metabase and compatibility layer to allow metabase calls to interact with new IIS 10.0 configuration store", + "State": 0 + }, + { + "FeatureName": "WAS-WindowsActivationService", + "DisplayName": "Windows Process Activation Service", + "Description": "Install Windows Process Activation Service", + "State": 0 + }, + { + "FeatureName": "WAS-ProcessModel", + "DisplayName": "Process Model", + "Description": "Install Process Model for the Windows Process Activation Service", + "State": 0 + }, + { + "FeatureName": "WAS-NetFxEnvironment", + "DisplayName": ".NET Environment", + "Description": "Install the .NET Environment for supporting managed code activation", + "State": 0 + }, + { + "FeatureName": "WAS-ConfigurationAPI", + "DisplayName": "Configuration APIs", + "Description": "Install managed code configuration APIs", + "State": 0 + }, + { + "FeatureName": "IIS-HostableWebCore", + "DisplayName": "Internet Information Services Hostable Web Core", + "Description": "Program your application to serve HTTP requests by using core IIS functionality.", + "State": 0 + }, + { + "FeatureName": "IIS-StaticContent", + "DisplayName": "Static Content", + "Description": "Serve .htm, .html, and image files from a Web site", + "State": 0 + }, + { + "FeatureName": "IIS-DefaultDocument", + "DisplayName": "Default Document", + "Description": "Allows you to specify a default file to be loaded when users do not specify a file in a request URL", + "State": 0 + }, + { + "FeatureName": "IIS-DirectoryBrowsing", + "DisplayName": "Directory Browsing", + "Description": "Allow clients to see the contents of a directory on your Web server", + "State": 0 + }, + { + "FeatureName": "IIS-WebDAV", + "DisplayName": "WebDAV Publishing", + "Description": "Publish and manage files on a Web server by using the HTTP protocol.", + "State": 0 + }, + { + "FeatureName": "IIS-WebSockets", + "DisplayName": "WebSocket Protocol", + "Description": "IIS 10.0 and ASP.NET 4.8 support writing server applications that communicate over the WebSocket Protocol.", + "State": 0 + }, + { + "FeatureName": "IIS-ApplicationInit", + "DisplayName": "Application Initialization", + "Description": "Application Initialization perform expensive web application initialization tasks before serving web pages.", + "State": 0 + }, + { + "FeatureName": "IIS-ISAPIFilter", + "DisplayName": "ISAPI Filters", + "Description": "Allow ISAPI filters to modify Web server behavior", + "State": 0 + }, + { + "FeatureName": "IIS-ISAPIExtensions", + "DisplayName": "ISAPI Extensions", + "Description": "Allow ISAPI extensions to handle client requests", + "State": 0 + }, + { + "FeatureName": "IIS-ASPNET", + "DisplayName": "ASP.NET 3.5", + "Description": "Enable your Web server to host ASP.NET 3.5 applications", + "State": 0 + }, + { + "FeatureName": "IIS-ASPNET45", + "DisplayName": "ASP.NET 4.8", + "Description": "Enable your Web server to host ASP.NET v4.8 applications", + "State": 0 + }, + { + "FeatureName": "IIS-ASP", + "DisplayName": "ASP", + "Description": "Enable your Web server to host Classic ASP applications", + "State": 0 + }, + { + "FeatureName": "IIS-CGI", + "DisplayName": "CGI", + "Description": "Enable support for CGI executables", + "State": 0 + }, + { + "FeatureName": "IIS-ServerSideIncludes", + "DisplayName": "Server-Side Includes", + "Description": "Serve .stm, .shtm, and .shtml files from a Web site", + "State": 0 + }, + { + "FeatureName": "IIS-CustomLogging", + "DisplayName": "Custom Logging", + "Description": "Enable support for custom logging for Web servers, sites, and applications", + "State": 0 + }, + { + "FeatureName": "IIS-BasicAuthentication", + "DisplayName": "Basic Authentication", + "Description": "Require a valid Windows user name and password for connection.", + "State": 0 + }, + { + "FeatureName": "IIS-HttpCompressionStatic", + "DisplayName": "Static Content Compression", + "Description": "Compress static content before returning it to a client", + "State": 0 + }, + { + "FeatureName": "IIS-ManagementConsole", + "DisplayName": "IIS Management Console", + "Description": "Install Web server Management Console which supports management of local and remote Web servers.", + "State": 0 + }, + { + "FeatureName": "IIS-ManagementService", + "DisplayName": "IIS Management Service", + "Description": "Allow the web server to be managed remotely from another computer via the Web server Management Console", + "State": 0 + }, + { + "FeatureName": "IIS-WMICompatibility", + "DisplayName": "IIS 6 WMI Compatibility", + "Description": "Install IIS 6.0 WMI scripting interfaces", + "State": 0 + }, + { + "FeatureName": "IIS-LegacyScripts", + "DisplayName": "IIS 6 Scripting Tools", + "Description": "Install IIS 6.0 configuration scripts", + "State": 0 + }, + { + "FeatureName": "IIS-LegacySnapIn", + "DisplayName": "IIS 6 Management Console", + "Description": "Install the IIS 6.0 Management Console. Provides support for administration of remote IIS 6.0 servers from this computer.", + "State": 0 + }, + { + "FeatureName": "IIS-FTPServer", + "DisplayName": "FTP Server", + "Description": "Enable your server to transfer files by using the FTP protocol.", + "State": 0 + }, + { + "FeatureName": "IIS-FTPSvc", + "DisplayName": "FTP Service", + "Description": "Enable FTP publishing on a Web server.", + "State": 0 + }, + { + "FeatureName": "IIS-FTPExtensibility", + "DisplayName": "FTP Extensibility", + "Description": "Customize FTP publishing by writing your own software extensions.", + "State": 0 + }, + { + "FeatureName": "MSMQ-Container", + "DisplayName": "Microsoft Message Queue (MSMQ) Server", + "Description": "Microsoft Message Queue (MSMQ) Server.", + "State": 0 + }, + { + "FeatureName": "MSMQ-DCOMProxy", + "DisplayName": "MSMQ DCOM Proxy", + "Description": "The DCOM proxy feature enables MSMQ applications to use MSMQ DCOM API to connect to a remote MSMQ Server.", + "State": 0 + }, + { + "FeatureName": "MSMQ-Server", + "DisplayName": "Microsoft Message Queue (MSMQ) Server Core", + "Description": "This feature installs the core components of MSMQ which enables you to perform basic Message queuing functions. This feature is a minimum requirement.", + "State": 0 + }, + { + "FeatureName": "MSMQ-ADIntegration", + "DisplayName": "MSMQ Active Directory Domain Services Integration", + "Description": "Active Directory Domain Services Integration feature enables publishing of queue properties to Active Directory Domain Services, out-of-the-box authentication and encryption of messages using certificates registered in Active Directory Domain Services, and routing of messages across Windows sites. This feature becomes operational only when the computer joins a domain.", + "State": 0 + }, + { + "FeatureName": "MSMQ-HTTP", + "DisplayName": "MSMQ HTTP Support", + "Description": "The HTTP Support feature allows you to expose a queue to the internet such that applications can send messages to the queue using HTTP protocol. This feature requires Internet Information Server.", + "State": 0 + }, + { + "FeatureName": "MSMQ-Multicast", + "DisplayName": "Multicasting Support", + "Description": "The Multicast support feature enables you to send messages to a Multicast IPAddress. Queues can be associated with a Multicast IPAddress. Messages sent to a Multicast IPAddress will be delivered to the queues that are associated with that IPAddress.", + "State": 0 + }, + { + "FeatureName": "MSMQ-Triggers", + "DisplayName": "MSMQ Triggers", + "Description": "Message Queue Triggers enables the invocation of a COM component or an executable depending on the filters that you define for the incoming messages in a given queue.", + "State": 0 + }, + { + "FeatureName": "IIS-CertProvider", + "DisplayName": "Centralized SSL Certificate Support", + "Description": "Centralized SSL Certificate Support enables you to manage SSL server certificates centrally using a file share. Maintaining SSL server certificates on a file share simplifies management since there is one place to manage them.", + "State": 0 + }, + { + "FeatureName": "IIS-WindowsAuthentication", + "DisplayName": "Windows Authentication", + "Description": "Authenticate clients by using NTLM or Kerberos.", + "State": 0 + }, + { + "FeatureName": "IIS-DigestAuthentication", + "DisplayName": "Digest Authentication", + "Description": "Authenticate clients by sending a password hash to a Windows domain controller.", + "State": 0 + }, + { + "FeatureName": "IIS-ClientCertificateMappingAuthentication", + "DisplayName": "Client Certificate Mapping Authentication", + "Description": "Authenticate client certificates with Active Directory accounts.", + "State": 0 + }, + { + "FeatureName": "IIS-IISCertificateMappingAuthentication", + "DisplayName": "IIS Client Certificate Mapping Authentication", + "Description": "Map client certificates 1-to-1 or many-to-1 to a Windows security identity.", + "State": 0 + }, + { + "FeatureName": "IIS-ODBCLogging", + "DisplayName": "ODBC Logging", + "Description": "Enable support for logging to an ODBC-compliant database.", + "State": 0 + }, + { + "FeatureName": "NetFx4-AdvSrvs", + "DisplayName": ".NET Framework 4.8 Advanced Services", + "Description": ".NET Framework 4.8 Advanced Services", + "State": 2 + }, + { + "FeatureName": "NetFx4Extended-ASPNET45", + "DisplayName": "ASP.NET 4.8", + "Description": "ASP.NET 4.8", + "State": 0 + }, + { + "FeatureName": "SearchEngine-Client-Package", + "DisplayName": "Windows Search", + "Description": "Provides content indexing, property caching, and search results for files, e-mail, and other content.", + "State": 2 + }, + { + "FeatureName": "Microsoft-RemoteDesktopConnection", + "DisplayName": "Remote Desktop Connection", + "Description": "The Remote Desktop Connection application.", + "State": 2 + }, + { + "FeatureName": "TIFFIFilter", + "DisplayName": "Windows TIFF IFilter", + "Description": "Enables the indexing and searching of Tagged Image File Format (TIFF) files using Optical Character Recognition (OCR).", + "State": 0 + }, + { + "FeatureName": "WorkFolders-Client", + "DisplayName": "Work Folders Client", + "Description": "Allows file synchronization with a configured file server.", + "State": 2 + }, + { + "FeatureName": "Printing-Foundation-Features", + "DisplayName": "Print and Document Services", + "Description": "Enable print, fax, and scan tasks on this computer", + "State": 2 + }, + { + "FeatureName": "Printing-Foundation-InternetPrinting-Client", + "DisplayName": "Internet Printing Client", + "Description": "Enables clients to use HTTP to connect to printers on Web print servers", + "State": 2 + }, + { + "FeatureName": "Printing-Foundation-LPDPrintService", + "DisplayName": "LPD Print Service", + "Description": "Makes your Windows computer work as a Line Printer Daemon (LPD) and Remote Line Printer client", + "State": 0 + }, + { + "FeatureName": "Printing-Foundation-LPRPortMonitor", + "DisplayName": "LPR Port Monitor", + "Description": "Enables clients to print to TCP/IP printers connected to a Unix (or VAX) server", + "State": 0 + }, + { + "FeatureName": "HypervisorPlatform", + "DisplayName": "Windows Hypervisor Platform", + "Description": "Enables virtualization software to run on the Windows hypervisor", + "State": 0 + }, + { + "FeatureName": "VirtualMachinePlatform", + "DisplayName": "Virtual Machine Platform", + "Description": "Enables platform support for virtual machines", + "State": 2 + }, + { + "FeatureName": "Microsoft-Windows-Subsystem-Linux", + "DisplayName": "Windows Subsystem for Linux", + "Description": "Provides services and environments for running native user-mode Linux shells and tools on Windows.", + "State": 2 + }, + { + "FeatureName": "Client-ProjFS", + "DisplayName": "Windows Projected File System", + "Description": "Enables Windows Projected File System", + "State": 0 + }, + { + "FeatureName": "Containers-DisposableClientVM", + "DisplayName": "Windows Sandbox", + "Description": "Enables the dependencies required to run Windows Sandbox scenarios.", + "State": 0 + }, + { + "FeatureName": "Microsoft-Hyper-V-All", + "DisplayName": "Hyper-V", + "Description": "Provides services and management tools for creating and running virtual machines and their resources.", + "State": 0 + }, + { + "FeatureName": "Microsoft-Hyper-V", + "DisplayName": "Hyper-V Platform", + "Description": "Provides the services that you can use to create and manage virtual machines and their resources.", + "State": 0 + }, + { + "FeatureName": "Microsoft-Hyper-V-Tools-All", + "DisplayName": "Hyper-V Management Tools", + "Description": "Includes GUI and command-line tools for managing Hyper-V.", + "State": 0 + }, + { + "FeatureName": "Microsoft-Hyper-V-Management-PowerShell", + "DisplayName": "Hyper-V Module for Windows PowerShell", + "Description": "Includes Windows PowerShell cmdlets for managing Hyper-V.", + "State": 0 + }, + { + "FeatureName": "Microsoft-Hyper-V-Hypervisor", + "DisplayName": "Hyper-V Hypervisor", + "Description": "Provides the Hyper-V Hypervisor.", + "State": 0 + }, + { + "FeatureName": "Microsoft-Hyper-V-Services", + "DisplayName": "Hyper-V Services", + "Description": "Provides the services that you can use to create and manage virtual machines and their resources.", + "State": 0 + }, + { + "FeatureName": "Microsoft-Hyper-V-Management-Clients", + "DisplayName": "Hyper-V GUI Management Tools", + "Description": "Includes the Hyper-V Manager snap-in and Virtual Machine Connection tool.", + "State": 0 + }, + { + "FeatureName": "Client-DeviceLockdown", + "DisplayName": "Device Lockdown", + "Description": "Services and tools to provide a controlled and specialized experience for the end user of a device", + "State": 0 + }, + { + "FeatureName": "Client-EmbeddedShellLauncher", + "DisplayName": "Shell Launcher", + "Description": "Launches an alternate shell instead of the default Windows shell", + "State": 0 + }, + { + "FeatureName": "Client-EmbeddedBootExp", + "DisplayName": "Unbranded Boot", + "Description": "Suppresses Windows elements that appear when Windows starts, resumes or encounters unrecovered errors", + "State": 0 + }, + { + "FeatureName": "Client-EmbeddedLogon", + "DisplayName": "Custom Logon", + "Description": "Enables customized logon experiences", + "State": 0 + }, + { + "FeatureName": "Client-KeyboardFilter", + "DisplayName": "Keyboard Filter", + "Description": "Enables controls to suppress undesirable key presses or key combinations", + "State": 0 + }, + { + "FeatureName": "Client-UnifiedWriteFilter", + "DisplayName": "Unified Write Filter", + "Description": "Installs services and tools to protect physical media from write operations", + "State": 0 + }, + { + "FeatureName": "DataCenterBridging", + "DisplayName": "Data Center Bridging", + "Description": "IEEE Data Center Bridging", + "State": 0 + }, + { + "FeatureName": "DirectoryServices-ADAM-Client", + "DisplayName": "Active Directory Lightweight Directory Services", + "Description": "This installs Active Directory Lightweight Directory Services (AD LDS).", + "State": 0 + }, + { + "FeatureName": "Windows-Defender-ApplicationGuard", + "DisplayName": "Microsoft Defender Application Guard", + "Description": "Offers a secure container for internet browsing", + "State": 0 + }, + { + "FeatureName": "Containers", + "DisplayName": "Containers", + "Description": "Provides services and tools to create and manage Windows Server Containers and their resources.", + "State": 0 + }, + { + "FeatureName": "Containers-HNS", + "DisplayName": "", + "Description": "", + "State": 0 + }, + { + "FeatureName": "Containers-SDN", + "DisplayName": "", + "Description": "", + "State": 0 + }, + { + "FeatureName": "SMB1Protocol", + "DisplayName": "SMB 1.0/CIFS File Sharing Support", + "Description": "Support for the SMB 1.0/CIFS file sharing protocol, and the Computer Browser protocol.", + "State": 0 + }, + { + "FeatureName": "SMB1Protocol-Client", + "DisplayName": "SMB 1.0/CIFS Client", + "Description": "Support for the SMB 1.0/CIFS client for accessing legacy servers.", + "State": 0 + }, + { + "FeatureName": "SMB1Protocol-Server", + "DisplayName": "SMB 1.0/CIFS Server", + "Description": "Support for the SMB 1.0/CIFS file server for sharing data with legacy clients and browsing the network neighborhood.", + "State": 0 + } +] diff --git a/providers/os/resources/windows/testdata/optionalfeatures2.json b/providers/os/resources/windows/testdata/optionalfeatures2.json new file mode 100644 index 0000000000000000000000000000000000000000..fe1f983ef2543a94a493cd2923c792f9961093a7 GIT binary patch literal 127513 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