One of the common things with Windows is to activate or deactivate while provisioning a machine are Features.
Good for us there is a CSP available since Windows 1903 to manage those.
Disclaimer: While this CSP is in Windows 10, this is an undocumented feature, I can’t guarantee that this will 100% work in the future, also, all my testing were done with Workspace ONE UEM which allow you to send any command to the devices and this worked perfectly.
Get the feature name
With Windows 10, there is 2 types of feature, Optional Feature and Feature On Demand.
To use the CSP we need the real/internal name of those feature
Optional Features
Optional features are part of the OS, like IIS, Hyper-V and so on.
To get the list of Optional Feature available and their name, we use this PowerShell command
Get-WindowsOptionalFeature -Online | Format-Table
Features On Demand
Feature On Demand can be added at anytime like an application, this currently include language pack (OCR, Text to Speech, Font, etc.), RSAT Tools, .NET Fx3 among others.
On demand features don’t use the concept of parent like the optional does, i.e IIS is the parent of the FTP server, it use the concept of satellites and dependencies (introduced in 1809) which are handled by the CSP. E.g: RSAT have satellites and dependencies.
To get the list of Feature On Demand, use the following PowerShell command.
Get-WindowsCapability -Online | Format-Table
It returns the name and the current state of the feature.
More detail also here : https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/features-on-demand-non-language-fod
Description of the CSP
OptionalFeature CSP is not available in the online documentation. However the DDF file is available. This the definition file of the CSP so we know how to use it.
There is 3 node in the CSP, which straight forward to understand.
-
Enable
: To enable a feature -
Disable
: To disable a feature -
Inventory
: To return a list of feature.
We will see that the behavior of the CSP is the same as the PowerShell commands and their switches. PowerShell equivalent are detailed when they exist.
The CSP store the information in the following registry key.
HKEY_LOCAL_MACHINE\SYSTEM\Setup\CSP\OptionalFeatures
Enable a Feature
In the Enable
node we have, FeatureName
which have to be changed by the feature name, optional or on demand, then inside we have:
- Enable
- LimitWUAccess
- EnableParentFeatures
- Status
- ErrorCode
The node use the following registry key to store information
HKEY_LOCAL_MACHINE\SYSTEM\Setup\CSP\OptionalFeatures\Enable
Enable
./Device/Vendor/MSFT/OptionalFeatures/Enable/<FeatureName>/Enable
This leaf notify the device to begin the installation of the feature
No notification is sent back to the MDM server after the feature have been enabled. It supportExec
.
PowerShell equivalent: Enable-WindowsOptionalFeature -online
and Add-WindowsCapability -online
LimitWUAccess
./Device/Vendor/MSFT/OptionalFeatures/Enable/<FeatureName>/LimitWUAccess
This leaf define if Windows Update can be reached or not to download the feature. The type is Boolean
and it support Get
, Add
, Delete
, and Replace
.
-
True
: Use the Alternate Source defined in the GPO to download. -
False
: Use the Alternate Source defined in the GPO then use Windows Update to download.
The group policy setting Specify settings for optional component installation and component repair is located in Computer Configuration > Administrative Templates > System
This policy allow to define an Alternate Source for the package to be downloaded usefull on closed or filtered network.
You can follow this article Configure a Windows Repair Source to know more about it.
Powershell equivalent: -LimitAccess
switch for Enable-WindowsOptionalFeature
and Add-WindowsCapability
EnableParentFeature
./Device/Vendor/MSFT/OptionalFeatures/Enable/<FeatureName>/EnableParentFeature
EnableParentFeature control the installation of the parent feature. The type is Boolean
and it support Get
, Add
, Delete
, and Replace
.
-
true
: Install parent feature and all of its default dependencies. -
false
: Only enable the feature.
If the feature have dependencies on the parent, e.g: FTP server requires IIS, then you need to enable the parent feature while enabling the feature itself.
When enabling the parent, it will install the default dependencies of each parent, so you may have more than what it is required. This behavior is the same between PowerShell and the CSP.
Below is an example for FTP Server installation, on the left done via GUI, on the right with PowerShell or the CSP:
Feature Installed via GUI | Feature Installed via CSP or PS |
---|---|
IIS-WebServerRole | IIS-WebServerRole |
IIS-FTPServer | IIS-WebServer |
IIS-FTPSvc | IIS-CommonHttpFeatures |
IIS-HttpErrors | |
IIS-ApplicationDevelopment | |
IIS-HealthAndDiagnostics | |
IIS-HttpLogging | |
IIS-Security | |
IIS-RequestFiltering | |
IIS-Performance | |
IIS-WebServerManagementTools | |
IIS-StaticContent | |
IIS-DefaultDocument | |
IIS-DirectoryBrowsing | |
IIS-HttpCompressionStatic | |
IIS-ManagementConsole | |
IIS-FTPServer | |
IIS-FTPSvc |
Powershell equivalent: -All
for Enable-WindowsOptionalFeature
, Add-WindowsCapability
don’t use the concept of parent.
Status
./Device/Vendor/MSFT/OptionalFeatures/Enable/<FeatureName>/Status
This leaf return the status of the last enable executed command. Type is integer
support only Get
.The value are:
-
1
: Success -
2
: Pending -
16
: Action failed
ErrorCode
./Device/Vendor/MSFT/OptionalFeatures/Enable/<FeatureName>/ErrorCode
This leaf return the HRESULT (Win32 error) of the last enable executed command. Type is integer
and support only Get
.
Examples
Telnet Client
Telnet client is a simple optional feature and don’t have any parents, we can omit the EnableParent
leaf. We can use the following SyncML.
<Exec>
<CmdID>3</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Enable/TelnetClient/Enable
</LocURI>
</Target>
<Meta>
<Format xmlns="syncml:metinf">chr</Format>
<Type>text/plain</Type>
</Meta>
<Data></Data>
</Item>
</Exec>
.Net Framework 3.5
The .NET Framework 3.5 is not part of Windows 10 but many times it is required by applications. It is available as a feature on demand.
Note: the ~
are part of the feature name.
<Exec>
<CmdID>3</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Enable/NetFX3~~~~/Enable
</LocURI>
</Target>
<Meta>
<Format xmlns="syncml:metinf">chr</Format>
<Type>text/plain</Type>
</Meta>
<Data></Data>
</Item>
</Exec>
Keyboard Filter
Client-KeyboardFilter is part of Device Lockdown optional feature so we need to specify the EnableParentFeatures
leaf, we put it at true
.
<Exec>
<CmdID>3</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Enable/Client-KeyboardFilter/Enable
</LocURI>
</Target>
<Meta>
<Format xmlns="syncml:metinf">chr</Format>
<Type>text/plain</Type>
</Meta>
<Data></Data>
</Item>
</Exec>
<Replace>
<CmdID>7</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Enable/Client-KeyboardFilter/EnableParentFeatures
</LocURI>
</Target>
<Meta>
<Format xmlns="syncml:metinf">bool</Format>
<Type>text/plain</Type>
</Meta>
<Data>true</Data>
</Item>
</Replace>
Disable a Feature
In the Disable
node we have, FeatureName
which have to be changed by the feature name, optional or on demand, then inside we have:
- Disable
- Status
- ErrorCode
The node use the following registry key to store information
HKEY_LOCAL_MACHINE\SYSTEM\Setup\CSP\OptionalFeatures\Disable
Disable
./Device/Vendor/MSFT/OptionalFeatures/Disable/<FeatureName>/Disable
This leaf notify the device to begin the removal of the feature
No notification is sent back to the MDM server after the feature have been disabled. It support Exec
.
PowerShell equivalent: Disable-WindowsOptionalFeature -online
and Remove-WindowsCapability -online
Status
./Device/Vendor/MSFT/OptionalFeatures/Disable/<FeatureName>/Status
This leaf return the status of the last enable executed command. Type is integer
support only Get
.The value are:
-
1
: Success -
2
: Pending -
16
: Action failed
ErrorCode
./Device/Vendor/MSFT/OptionalFeatures/Disable/<FeatureName>/ErrorCode
This leaf return the HRESULT (Win32 error) of the last enable executed command. Type is integer
and support only Get
.
Examples
SMB 1.0/CIFS File Sharing Support
SMBv1 is one of the feature that a lot of customer look to disable for security purpose. While new Windows 10, from 1709, have SMBv1 disabled by default, system installed with earlier version which have been upgraded still have SMBv1 enabled.
To disable the feature completely, we are targeting the parent feature, SMB1Protocol
, to remove child features at the same time.
<Exec>
<CmdID>3</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Disable/SMB1Protocol/Disable
</LocURI>
</Target>
<Meta>
<Format xmlns="syncml:metinf">chr</Format>
<Type>text/plain</Type>
</Meta>
<Data></Data>
</Item>
</Exec>
Inventory
In the Inventory
node we have:
- OnlyEnabledList
- GetList
- FeatureList
- Status
- ErrorCode
This node use the following registry key to store information
HKEY_LOCAL_MACHINE\SYSTEM\Setup\CSP\OptionalFeatures\Inventory
OnlyEnabledList
./Device/Vendor/MSFT/OptionalFeatures/Inventory/OnlyEnabledList
This leaf is to configure the inventory to return. Type is Boolean
and support Get
and Replace
.
-
Get
: Get the current value of the setting, return true or false. -
Replace
: Modify the setting
-
true
: Return the list of enabled optional features and feature on demands. -
false
: Return all features available (optional and on demands) for the device.
The parameter is stored in the registry, as a DWORD
value, here:
HKEY_LOCAL_MACHINE\SYSTEM\Setup\CSP\OptionalFeatures\Inventory\EnabledListOnly
GetList
./Device/Vendor/MSFT/OptionalFeatures/Inventory/GetList
This leaf generate the list of features, it use OnlyEnabledList
setting to generate the list accordingly. It support Exec
FeatureList
./Device/Vendor/MSFT/OptionalFeatures/Inventory/FeatureList
This leaf return the feature list created by GetList
. If a feature is installed with Enable
and GetList
haven’t been called then the feature list won’t be up-to-date.
The feature list separated with UTF-8 Unicode character U+F000
which is EF 80 80
in hex.
You can decode the feature list with PowerShell using the split method.
[XML] $SyncML = Get-Content .\SyncML.xml -Encoding UTF8
$Data = $SyncML.SyncML.SyncBody.Results.Item.Data
$Data.Split([regex]::Unescape(""))
The list is stored in the registry, as a REG_SZ value, here:
HKEY_LOCAL_MACHINE\SYSTEM\Setup\CSP\OptionalFeatures\Inventory\FeatureList
Usage
The process to use the Inventory
node is:
- Set the type of list to All or Installed Only with
OnlyEnabledList
- Generate the list with
GetList
- Retrieve the list with
FeatureList
Status
./Device/Vendor/MSFT/OptionalFeatures/Inventory/Status
This leaf return the status of the last enable executed command. Type is integer
support only Get
.The value are:
-
1
: Success -
2
: Pending -
16
: Action failed
ErrorCode
./Device/Vendor/MSFT/OptionalFeatures/Inventory/ErrorCode
This leaf return the HRESULT (Win32 error) of the last enable executed command. Type is integer
and support only Get
.
Example
Here’s a SyncML example of the process to generate the list of installed feature
Set the type of list to Installed Only
<Replace>
<CmdID>1</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Inventory/OnlyEnabledList
</LocURI>
</Target>
<Meta>
<Format xmlns="syncml:metinf">bool</Format>
<Type>text/plain</Type>
</Meta>
<Data>true</Data>
</Item>
</Replace>
Generate the list
<Exec>
<CmdID>2</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Inventory/GetList
</LocURI>
</Target>
<Meta>
<Format xmlns="syncml:metinf">chr</Format>
<Type>text/plain</Type>
</Meta>
<Data></Data>
</Item>
</Exec>
Retrieve the list
<Get>
<CmdID>3</CmdID>
<Item>
<Target>
<LocURI>
./Device/Vendor/MSFT/OptionalFeatures/Inventory/FeatureList
</LocURI>
</Target>
</Item>
</Get>