-
Notifications
You must be signed in to change notification settings - Fork 58
Add Microsoft.Windows/OptionalFeatureList resource
#1432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
SteveL-MSFT
merged 8 commits into
PowerShell:main
from
SteveL-MSFT:optionalfeatures-resource
Mar 14, 2026
+1,326
−1
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
e18e479
Add `Microsoft.Windows/OptionalFeatureList` resource
0f31d01
Add set operation
bf7bb10
code improvements
f37b61c
Add _restartRequired and fix tests for non-Windows
9345a39
Potential fix for pull request finding
SteveL-MSFT 09e273b
address copilot feedback
ca53f7b
Potential fix for pull request finding
SteveL-MSFT a19b612
address copilot feedack
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "Name": "dism_dsc", | ||
| "Kind": "Resource", | ||
| "IsRust": true, | ||
| "SupportedPlatformOS": "Windows", | ||
| "Binaries": ["dism_dsc"], | ||
| "CopyFiles": { | ||
| "Windows": ["optionalfeature.dsc.resource.json"] | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| [package] | ||
| name = "dism_dsc" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| [[bin]] | ||
| name = "dism_dsc" | ||
| path = "src/main.rs" | ||
|
|
||
| [dependencies] | ||
| rust-i18n = { workspace = true } | ||
| serde = { workspace = true } | ||
| serde_json = { workspace = true } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| _version = 1 | ||
|
|
||
| [main] | ||
| missingOperation = "Missing operation argument" | ||
| usage = "Usage: dism_dsc <get|set|export>" | ||
| windowsOnly = "This resource is only supported on Windows" | ||
| unknownOperation = "Unknown operation '%{operation}'" | ||
| errorReadingInput = "Error reading input: %{err}" | ||
|
|
||
| [get] | ||
| failedParseInput = "Failed to parse input: %{err}" | ||
| featuresArrayEmpty = "Features array cannot be empty for get operation" | ||
| featureNameRequired = "featureName is required for get operation" | ||
| failedSerializeOutput = "Failed to serialize output: %{err}" | ||
|
|
||
| [export] | ||
| failedParseInput = "Failed to parse input: %{err}" | ||
| failedSerializeOutput = "Failed to serialize output: %{err}" | ||
|
|
||
| [set] | ||
| failedParseInput = "Failed to parse input: %{err}" | ||
| featuresArrayEmpty = "Features array cannot be empty for set operation" | ||
| featureNameRequired = "featureName is required for set operation" | ||
| stateRequired = "state is required for set operation" | ||
| unsupportedDesiredState = "Unsupported desired state '%{state}'. Supported states for set are: Installed, NotPresent, Removed" | ||
| failedSerializeOutput = "Failed to serialize output: %{err}" | ||
|
|
||
| [dism] | ||
| failedLoadLibrary = "Failed to load dismapi.dll. Ensure DISM is available on this system." | ||
| functionNotFound = "Failed to find function '%{name}' in dismapi.dll" | ||
| initializeFailed = "DismInitialize failed: HRESULT %{hr}" | ||
| openSessionFailed = "DismOpenSession failed: HRESULT %{hr}" | ||
| getFeatureInfoFailed = "DismGetFeatureInfo failed for '%{name}': HRESULT %{hr}" | ||
| enableFeatureFailed = "DismEnableFeature failed for '%{name}': HRESULT %{hr}" | ||
| disableFeatureFailed = "DismDisableFeature failed for '%{name}': HRESULT %{hr}" | ||
| getFeaturesFailed = "DismGetFeatures failed: HRESULT %{hr}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| { | ||
| "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", | ||
| "description": "Manage Windows Optional Features using the DISM API.", | ||
| "tags": [ | ||
| "windows", | ||
| "dism", | ||
| "optionalfeature", | ||
| "feature" | ||
| ], | ||
| "type": "Microsoft.Windows/OptionalFeatureList", | ||
| "version": "0.1.0", | ||
| "get": { | ||
| "executable": "dism_dsc", | ||
| "args": [ | ||
| "get" | ||
| ], | ||
| "input": "stdin", | ||
| "requireSecurityContext": "elevated" | ||
| }, | ||
| "set": { | ||
| "executable": "dism_dsc", | ||
| "args": [ | ||
| "set" | ||
| ], | ||
| "input": "stdin", | ||
| "implementsPretest": false, | ||
| "return": "state", | ||
| "requireSecurityContext": "elevated" | ||
| }, | ||
| "export": { | ||
| "executable": "dism_dsc", | ||
| "args": [ | ||
| "export" | ||
| ], | ||
| "input": "stdin", | ||
| "requireSecurityContext": "elevated" | ||
| }, | ||
| "schema": { | ||
| "embedded": { | ||
| "$schema": "http://json-schema.org/draft-07/schema#", | ||
| "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/resources/Microsoft.Windows/OptionalFeatureList/v0.1.0/schema.json", | ||
| "title": "Windows Optional Feature", | ||
| "description": "Manage Windows Optional Features using the DISM API. Supports get, set, and export operations.\n\nhttps://learn.microsoft.com/powershell/dsc/reference/microsoft.windows/optionalfeaturelist/resource\n", | ||
| "markdownDescription": "The `Microsoft.Windows/OptionalFeatureList` resource enables you to manage Windows Optional Features using the DISM API. Supports enabling (`Installed`) and disabling (`NotPresent`, `Removed`) features.\n\n[Online documentation][01]\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/microsoft.windows/optionalfeaturelist/resource\n", | ||
| "type": "object", | ||
| "additionalProperties": false, | ||
| "required": [ | ||
| "features" | ||
| ], | ||
| "properties": { | ||
| "_restartRequired": { | ||
| "type": "array", | ||
| "title": "Restart required", | ||
| "description": "Indicates that a system restart is required to complete the state change. Returned by the set operation when DISM reports that a reboot is needed.", | ||
| "items": { | ||
| "type": "object", | ||
| "additionalProperties": true | ||
| } | ||
| }, | ||
| "features": { | ||
| "type": "array", | ||
| "title": "Features", | ||
| "description": "An array of optional feature filters or feature information objects.", | ||
| "items": { | ||
| "type": "object", | ||
| "additionalProperties": false, | ||
| "properties": { | ||
| "featureName": { | ||
| "type": "string", | ||
| "title": "Feature name", | ||
| "description": "The name of the Windows optional feature. Required for get operation. For export operation, this is optional and wildcards (*) are supported for case-insensitive filtering." | ||
| }, | ||
| "_exist": { | ||
| "type": "boolean", | ||
| "title": "Exists", | ||
| "description": "Indicates whether the feature exists on the system. Set to false when the requested feature name is not recognized by DISM." | ||
| }, | ||
| "state": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "NotPresent", | ||
| "UninstallPending", | ||
| "Staged", | ||
| "Removed", | ||
| "Installed", | ||
| "InstallPending", | ||
| "Superseded", | ||
| "PartiallyInstalled" | ||
| ], | ||
| "title": "Feature state", | ||
| "description": "The current state of the optional feature. For set operations, only Installed, NotPresent, and Removed are accepted; other states are returned by get and export operations and are not valid inputs for set."}, | ||
| "displayName": { | ||
| "type": "string", | ||
| "title": "Display name", | ||
| "description": "The display name of the optional feature. Returned by get and export operations. For export, wildcards (*) are supported for case-insensitive filtering." | ||
| }, | ||
| "description": { | ||
| "type": "string", | ||
| "title": "Description", | ||
| "description": "The description of the optional feature. Returned by get and export operations. For export, wildcards (*) are supported for case-insensitive filtering." | ||
| }, | ||
| "restartRequired": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "No", | ||
| "Possible", | ||
| "Required" | ||
| ], | ||
| "title": "Restart required", | ||
| "description": "Whether a restart is required after enabling or disabling the feature. This is a read-only property returned by get and export operations." | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| #[cfg(windows)] | ||
| mod optional_feature; | ||
|
|
||
| use rust_i18n::t; | ||
| use std::io::{self, Read, IsTerminal}; | ||
|
|
||
| rust_i18n::i18n!("locales", fallback = "en-us"); | ||
|
|
||
| fn read_stdin(required: bool) -> Result<String, String> { | ||
| let mut buffer = String::new(); | ||
| if required || !io::stdin().is_terminal() { | ||
| io::stdin() | ||
| .read_to_string(&mut buffer) | ||
| .map_err(|e| t!("main.errorReadingInput", err = e).to_string())?; | ||
| } | ||
| Ok(buffer) | ||
| } | ||
|
|
||
| fn dispatch(handler: impl FnOnce(&str) -> Result<String, String>, stdin_required: bool) { | ||
| let buffer = match read_stdin(stdin_required) { | ||
| Ok(b) => b, | ||
| Err(e) => { | ||
| eprintln!("{e}"); | ||
| std::process::exit(1); | ||
| } | ||
| }; | ||
|
|
||
| match handler(&buffer) { | ||
| Ok(output) => { | ||
| println!("{output}"); | ||
| std::process::exit(0); | ||
| } | ||
| Err(e) => { | ||
| eprintln!("Error: {e}"); | ||
| std::process::exit(1); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(not(windows))] | ||
| fn main() { | ||
| eprintln!("Error: {}", t!("main.windowsOnly")); | ||
| std::process::exit(1); | ||
| } | ||
|
|
||
| #[cfg(windows)] | ||
| fn main() { | ||
| let args: Vec<String> = std::env::args().collect(); | ||
|
|
||
| if args.len() < 2 { | ||
| eprintln!("Error: {}", t!("main.missingOperation")); | ||
| eprintln!("{}", t!("main.usage")); | ||
| std::process::exit(1); | ||
| } | ||
|
|
||
| let operation = args[1].as_str(); | ||
|
|
||
| match operation { | ||
| "export" => dispatch(optional_feature::handle_export, false), | ||
| "get" => dispatch(optional_feature::handle_get, true), | ||
| "set" => dispatch(optional_feature::handle_set, true), | ||
| _ => { | ||
| eprintln!("{}", t!("main.unknownOperation", operation = operation)); | ||
| eprintln!("{}", t!("main.usage")); | ||
| std::process::exit(1); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.