Skip to content

feat: Windows optional features toggle tab#288

Merged
laurentiu021 merged 1 commit into
mainfrom
feat/windows-features
May 13, 2026
Merged

feat: Windows optional features toggle tab#288
laurentiu021 merged 1 commit into
mainfrom
feat/windows-features

Conversation

@laurentiu021

@laurentiu021 laurentiu021 commented May 13, 2026

Copy link
Copy Markdown
Owner

Summary

Replaces the Windows Features placeholder with a fully functional tab that lists, enables, and disables Windows optional features.

What changed

  • WindowsFeature.cs (new model) — Name, DisplayName, IsEnabled, RequiresReboot, Category, Status
  • WindowsFeaturesService.cs (new service) — wraps Get-WindowsOptionalFeature, Enable/Disable-WindowsOptionalFeature PowerShell commands
  • WindowsFeaturesViewModel.cs (new VM) — scan, toggle, filter, admin check, reboot tracking
  • WindowsFeaturesView.xaml (new view) — DataGrid with Category, Feature, State, Toggle button, Status columns
  • MainWindowViewModel — replaced WipWindowsFeatures placeholder with real WindowsFeaturesViewModel
  • ServiceRegistration — registered WindowsFeaturesService and VM
  • README — removed ⚙️ marker, added feature description
  • CHANGELOG — v0.46.0 entry

Features

  • Lists all Windows optional features with current state
  • Categorized: Virtualization, Networking, Development, Media & Print, Legacy, Other
  • Toggle enable/disable with confirmation dialog
  • Shows reboot-required status
  • Search/filter by name or category
  • Admin badge (shows if elevated)
  • Reboot pending indicator

Testing

  • 10 unit tests: ParseFeatureList (4), CategorizeFeature (2), HumanizeName (1), ViewModel state (1), Theory with 15 inline data cases
  • Both projects build with 0 errors

Closes #5

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced Windows Features tab to list, enable, and disable Windows optional features (Hyper-V, WSL, .NET 3.5, Telnet, and more)
    • Requires admin privileges for toggling features with confirmation prompts
    • Displays reboot requirement status
    • Includes search and filtering functionality
  • Tests

    • Added comprehensive unit tests for Windows Features functionality

Review Change Stack

- Add WindowsFeature model with category classification
- Add WindowsFeaturesService wrapping Get-WindowsOptionalFeature PowerShell
- Add WindowsFeaturesViewModel with scan, toggle, filter, admin check
- Add WindowsFeaturesView.xaml with DataGrid, category/state/toggle columns
- Replace WipWindowsFeatures placeholder with real implementation
- Register WindowsFeaturesService and VM in DI container
- Add 10 unit tests (ParseFeatureList, CategorizeFeature, HumanizeName, VM state)
- Update README: remove ⚙️ from Windows Features, add feature description
- Update CHANGELOG with v0.46.0 entry

Closes #5
@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR implements a complete Windows optional features management tab for the System group, adding PowerShell-backed functionality to list, toggle, and track Windows features with admin requirements, confirmation prompts, and reboot-required status indicators. The feature includes search/filtering and comprehensive unit test coverage.

Changes

Windows Features Management Tab

Layer / File(s) Summary
Windows Feature Data Model & Categorization
SysManager/SysManager/Models/WindowsFeature.cs
WindowsFeature is an ObservableObject with observable properties for feature name, display name, enabled state, reboot requirement, category, and status. CategorizeFeature() static method maps feature names to category strings (Virtualization, Development, Networking, Media & Print, Legacy, or Other) by matching uppercase name against substring patterns.
PowerShell Service Layer
SysManager/SysManager/Services/WindowsFeaturesService.cs
WindowsFeaturesService wraps PowerShellRunner to manage Windows optional features. ListFeaturesAsync() executes Get-WindowsOptionalFeature -Online and parses pipe-delimited output into WindowsFeature objects sorted by category and display name. EnableFeatureAsync() and DisableFeatureAsync() validate feature names via regex, execute feature commands with -NoRestart flag, capture RestartNeeded output to determine reboot requirement, and return success/reboot tuple. Internal helpers parse feature lists, humanize names by replacing delimiters with spaces, and validate names to alphanumeric, dot, and hyphen characters (1-128 length).
Service Layer Unit Tests
SysManager/SysManager.Tests/WindowsFeaturesTests.cs
Unit tests validate ParseFeatureList handling of empty input, correct parsing of valid pipe-delimited feature lines with state mapping, skipping blank/whitespace lines, and skipping invalid lines without separator. Parameterized tests for CategorizeFeature verify mapping across multiple feature types and fallback to "Other" for null/empty/whitespace. HumanizeName tests verify delimiter replacement. WindowsFeaturesViewModel initialization test asserts default empty collections, zero counts, empty filter text, and PendingReboot false.
ViewModel Commands, State & Filtering
SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs
WindowsFeaturesViewModel maintains AllFeatures and FilteredFeatures observable collections with live filtering driven by FilterText matching across display name, internal name, and category. Constructor initializes WindowsFeaturesService and elevation state via dependency injection. ScanAsync command clears collections, creates cancellation token source, queries features from service, populates collections, applies filtering, updates enabled count and summary text, with cancellation and error handling. ToggleFeatureAsync validates elevation requirement, prompts for confirmation, calls service enable/disable with fresh cancellation token, updates target feature's enabled state/reboot requirement/status and recomputes enabled count, with logging and error handling. Cancel command cancels in-flight operations; ApplyFilter rebuilds filtered list and updates summary. Dispose() cleans up cancellation token source.
User Interface & Data Binding
SysManager/SysManager/Views/WindowsFeaturesView.xaml, SysManager/SysManager/Views/WindowsFeaturesView.xaml.cs
WindowsFeaturesView WPF user control displays toolbar with Scan and Cancel command buttons, live search box bound to FilterText, conditional badges for reboot-pending and elevated-privilege status, and summary card. Read-only DataGrid binds to FilteredFeatures with columns for category, feature display name, enabled/disabled state text, per-feature toggle button linked to ToggleFeatureCommand, and status field with conditional color-coding ("Reboot required" orange, "Done" green, "Failed" red) and tooltip binding. Status bar includes progress bar bound to IsProgressIndeterminate and IsBusy, plus status message caption.
Dependency Injection & Navigation Wiring
SysManager/SysManager/ServiceRegistration.cs, SysManager/SysManager/ViewModels/MainWindowViewModel.cs
ServiceRegistration.ConfigureServices() registers WindowsFeaturesService and WindowsFeaturesViewModel as singleton DI services. MainWindowViewModel replaces placeholder WipWindowsFeatures property with real WindowsFeaturesViewModel property, resolving via DI in runtime constructor and manually constructing with runner in test/designer constructor. Sidebar navigation item for "Windows Features" updates to bind to WindowsFeatures viewmodel and display Views.WindowsFeaturesView; disposal logic switches from disposing placeholder to disposing real viewmodel in both paths. InitPlaceholders() no longer initializes WipWindowsFeatures.
Release Notes & Feature Documentation
CHANGELOG.md, README.md
CHANGELOG.md adds [0.46.0] entry (dated 2026-05-13) under Added section documenting Windows Features tab with capabilities: listing optional features, enabling/disabling with admin requirement, reboot-required status display, search/filter support, and references issue #5. README.md removes work-in-progress marker ("⚙️") from System group in Features sidebar table. Adds new "Windows Features" subsection to feature list describing optional feature listing, enable/disable toggling with confirmation dialogs, admin privilege requirement, reboot-required status indication, and search/filter functionality.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • laurentiu021/SystemManager#286: Dependency injection and service registration foundation used by this PR's WindowsFeaturesService and WindowsFeaturesViewModel DI wiring.

Poem

A rabbit hops through Windows features bright, 🐰
Toggling Hyper-V and WSL with delight,
With PowerShell whispers and MVVM grace,
Each reboot requirement finds its rightful place. ⚙️
Dang, this feature code is clean as can be! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Windows optional features toggle tab' clearly and concisely summarizes the main change: adding a functional Windows features management tab to the application.
Linked Issues check ✅ Passed The pull request comprehensively addresses all coding objectives from issue #5: listing features with state, per-feature toggles, category grouping, reboot requirement indication, admin requirement enforcement, and tab integration within the System group.
Out of Scope Changes check ✅ Passed All changes directly support the Windows Features implementation scope: model/service/viewmodel additions, UI view creation, DI registration, and documentation updates. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/windows-features

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter

Copy link
Copy Markdown

Comment on lines +119 to +140
foreach (var line in lines)
{
if (string.IsNullOrWhiteSpace(line)) continue;

var parts = line.Split('|', 2);
if (parts.Length < 2) continue;

var name = parts[0].Trim();
var state = parts[1].Trim();

if (string.IsNullOrWhiteSpace(name)) continue;

var isEnabled = state.Equals("Enabled", StringComparison.OrdinalIgnoreCase);

features.Add(new WindowsFeature
{
Name = name,
DisplayName = HumanizeName(name),
IsEnabled = isEnabled,
Category = WindowsFeature.CategorizeFeature(name)
});
}
Comment on lines +107 to +114
if (feature.IsEnabled)
{
(success, reboot) = await _service.DisableFeatureAsync(feature.Name, _cts.Token);
}
else
{
(success, reboot) = await _service.EnableFeatureAsync(feature.Name, _cts.Token);
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 145-152: Update the "Windows Features" docs to include the
fallback "Other" category so docs match the feature model/service; specifically
edit the "### Windows Features" section where the categories are listed (the
line that currently reads "Categorized: Virtualization, Networking, Development,
Media & Print, Legacy") and append or insert "Other" (e.g., "Categorized:
Virtualization, Networking, Development, Media & Print, Legacy, Other") and add
a brief note that "Other" is the fallback bucket used by the feature
model/service for uncategorized items.

In `@SysManager/SysManager/Services/WindowsFeaturesService.cs`:
- Line 131: The current mapping sets isEnabled only when state.Equals("Enabled",
...), which misses values like "Enabled with Payload Removed" or pending
variants; update the logic in WindowsFeaturesService.cs where the local variable
isEnabled is set from state to consider any state that starts with or contains
"Enabled" (e.g., use state?.Trim().StartsWith("Enabled",
StringComparison.OrdinalIgnoreCase) or state?.IndexOf("Enabled",
StringComparison.OrdinalIgnoreCase) >= 0) and ensure you null-check state before
calling methods so those variants are treated as enabled.
- Around line 33-41: The shared PowerShellRunner.LineReceived event handler
(attached in WindowsFeaturesService methods around RunProcessAsync with the
Collect handler) can be invoked concurrently across multiple async calls causing
cross-talk; serialize access by either acquiring the existing
OperationLockService from WindowsFeaturesViewModel before invoking
WindowsFeaturesService methods (follow the same lock pattern used elsewhere) or
add a private SemaphoreSlim (e.g., _runSemaphore) to WindowsFeaturesService and
await _runSemaphore.WaitAsync()/Release() around the sections that attach/detach
LineReceived and call RunProcessAsync so only one Collect handler is active at a
time.

In `@SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs`:
- Around line 50-52: The code disposes and replaces the CancellationTokenSource
field `_cts` without calling `_cts.Cancel()`, which can leave in-flight
`ScanAsync` operations using an orphaned token; before calling `_cts.Dispose()`
and assigning a new `CancellationTokenSource`, call `_cts.Cancel()` (check for
null) to signal any running work, then dispose and replace it; apply this change
in both places where `_cts` is replaced (the existing block around
`_cts?.Dispose(); _cts = new CancellationTokenSource();` and the other
replacement near the same pattern) so `ToggleFeatureAsync`/`ScanAsync`
interactions are properly cancelled.

In `@SysManager/SysManager/Views/WindowsFeaturesView.xaml`:
- Around line 45-52: Replace the emoji-only status markers in the two TextBlock
elements so they use plain, accessible labels (and optional icon controls)
instead of leading emoji; specifically update the TextBlocks that are inside the
Border elements bound to PendingReboot and IsElevated (the TextBlocks currently
with Text="⚠ Reboot pending" and Text="✓ Administrator") to use descriptive
plain text like "Reboot pending" and "Administrator" and, if an icon is desired,
use an Image/Icon control or an accessible glyph with AutomationProperties.Name
set, ensuring the PendingReboot and IsElevated bindings remain unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7be4ff2d-1372-485d-a34e-8734c0e9a94d

📥 Commits

Reviewing files that changed from the base of the PR and between c1a5a81 and 7e77358.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • README.md
  • SysManager/SysManager.Tests/WindowsFeaturesTests.cs
  • SysManager/SysManager/Models/WindowsFeature.cs
  • SysManager/SysManager/ServiceRegistration.cs
  • SysManager/SysManager/Services/WindowsFeaturesService.cs
  • SysManager/SysManager/ViewModels/MainWindowViewModel.cs
  • SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs
  • SysManager/SysManager/Views/WindowsFeaturesView.xaml
  • SysManager/SysManager/Views/WindowsFeaturesView.xaml.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build & unit tests
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (10)
CHANGELOG.md (1)

9-17: LGTM!

README.md (1)

46-46: LGTM!

SysManager/SysManager/ServiceRegistration.cs (1)

56-57: LGTM!

SysManager/SysManager/Views/WindowsFeaturesView.xaml.cs (1)

1-12: LGTM!

SysManager/SysManager/ViewModels/MainWindowViewModel.cs (1)

41-42: LGTM!

Also applies to: 104-105, 138-139, 187-188, 348-349

SysManager/SysManager/Views/WindowsFeaturesView.xaml (1)

1-44: LGTM!

Also applies to: 53-175

SysManager/SysManager/Services/WindowsFeaturesService.cs (1)

1-130: LGTM!

Also applies to: 132-161

SysManager/SysManager/Models/WindowsFeature.cs (1)

1-55: LGTM!

SysManager/SysManager.Tests/WindowsFeaturesTests.cs (1)

1-132: LGTM!

SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs (1)

1-49: LGTM!

Also applies to: 53-98, 102-181

Comment thread README.md
Comment on lines +145 to +152
### Windows Features
- Lists all Windows optional features with current state (Enabled/Disabled)
- Toggle enable/disable per feature with confirmation dialog
- Categorized: Virtualization, Networking, Development, Media & Print, Legacy
- Shows reboot-required status after toggling
- Search/filter across all features
- Requires administrator privileges for modifications

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include the “Other” category in the feature docs.

Line 148 lists categories but omits the fallback Other bucket used by the feature model/service, so docs can diverge from what users see in the UI.

Suggested doc tweak
-- Categorized: Virtualization, Networking, Development, Media & Print, Legacy
+- Categorized: Virtualization, Networking, Development, Media & Print, Legacy, Other
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### Windows Features
- Lists all Windows optional features with current state (Enabled/Disabled)
- Toggle enable/disable per feature with confirmation dialog
- Categorized: Virtualization, Networking, Development, Media & Print, Legacy
- Shows reboot-required status after toggling
- Search/filter across all features
- Requires administrator privileges for modifications
### Windows Features
- Lists all Windows optional features with current state (Enabled/Disabled)
- Toggle enable/disable per feature with confirmation dialog
- Categorized: Virtualization, Networking, Development, Media & Print, Legacy, Other
- Shows reboot-required status after toggling
- Search/filter across all features
- Requires administrator privileges for modifications
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 145 - 152, Update the "Windows Features" docs to
include the fallback "Other" category so docs match the feature model/service;
specifically edit the "### Windows Features" section where the categories are
listed (the line that currently reads "Categorized: Virtualization, Networking,
Development, Media & Print, Legacy") and append or insert "Other" (e.g.,
"Categorized: Virtualization, Networking, Development, Media & Print, Legacy,
Other") and add a brief note that "Other" is the fallback bucket used by the
feature model/service for uncategorized items.

Comment on lines +33 to +41
_runner.LineReceived += Collect;
try
{
await _runner.RunProcessAsync("powershell",
"-NoProfile -Command \"Get-WindowsOptionalFeature -Online | " +
"Select-Object FeatureName, State | " +
"ForEach-Object { $_.FeatureName + '|' + $_.State }\"", ct);
}
finally { _runner.LineReceived -= Collect; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect PowerShellRunner implementation for serialization and event dispatch semantics
fd -i "PowerShellRunner.cs" --exec sed -n '1,320p' {}

# 2) Locate synchronization primitives and LineReceived usage
rg -nP --type=cs -C3 'class\s+PowerShellRunner|event\s+.*LineReceived|RunProcessAsync\s*\(|SemaphoreSlim|lock\s*\('

# 3) Confirm whether any callers assume exclusive output capture via event subscription
rg -nP --type=cs -C2 'LineReceived\s*\+=|LineReceived\s*-='

Repository: laurentiu021/SystemManager

Length of output: 50382


🏁 Script executed:

# Check if WindowsFeaturesService or its callers use OperationLockService
rg -nP --type=cs -C3 "WindowsFeaturesService|OperationLockService" | head -100

Repository: laurentiu021/SystemManager

Length of output: 9427


🏁 Script executed:

# Search for actual concurrent calls to RunProcessAsync in the codebase
# Look for any async methods calling RunProcessAsync without await or Task.WhenAll scenarios
rg -nP --type=cs -B2 -A2 "RunProcessAsync" SysManager/SysManager/Services/WindowsFeaturesService.cs

Repository: laurentiu021/SystemManager

Length of output: 815


🏁 Script executed:

# Check if WindowsFeaturesService methods are decorated with synchronization attributes or use locks
sed -n '1,150p' SysManager/SysManager/Services/WindowsFeaturesService.cs

Repository: laurentiu021/SystemManager

Length of output: 5469


Prevent concurrent LineReceived event capture across multiple async operations on the shared PowerShellRunner instance.

Lines 33, 64, and 98 attach temporary event handlers during RunProcessAsync calls; if multiple service methods execute concurrently (which is currently possible since WindowsFeaturesViewModel does not use OperationLockService), output from unrelated processes will bleed between collectors, causing silent parsing failures or data corruption.

Recommended fixes:

  • Add OperationLockService synchronization in WindowsFeaturesViewModel (pattern used consistently elsewhere in codebase), or
  • Introduce a SemaphoreSlim in WindowsFeaturesService to serialize its public methods
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/Services/WindowsFeaturesService.cs` around lines 33 -
41, The shared PowerShellRunner.LineReceived event handler (attached in
WindowsFeaturesService methods around RunProcessAsync with the Collect handler)
can be invoked concurrently across multiple async calls causing cross-talk;
serialize access by either acquiring the existing OperationLockService from
WindowsFeaturesViewModel before invoking WindowsFeaturesService methods (follow
the same lock pattern used elsewhere) or add a private SemaphoreSlim (e.g.,
_runSemaphore) to WindowsFeaturesService and await
_runSemaphore.WaitAsync()/Release() around the sections that attach/detach
LineReceived and call RunProcessAsync so only one Collect handler is active at a
time.


if (string.IsNullOrWhiteSpace(name)) continue;

var isEnabled = state.Equals("Enabled", StringComparison.OrdinalIgnoreCase);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle non-exact enabled states when mapping IsEnabled.

Line 131 only treats exact "Enabled" as enabled; states like "Enabled with Payload Removed" (and pending variants) will be shown as disabled.

Suggested parsing adjustment
- var isEnabled = state.Equals("Enabled", StringComparison.OrdinalIgnoreCase);
+ var isEnabled =
+     state.StartsWith("Enabled", StringComparison.OrdinalIgnoreCase) ||
+     state.StartsWith("Enable Pending", StringComparison.OrdinalIgnoreCase);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var isEnabled = state.Equals("Enabled", StringComparison.OrdinalIgnoreCase);
var isEnabled =
state.StartsWith("Enabled", StringComparison.OrdinalIgnoreCase) ||
state.StartsWith("Enable Pending", StringComparison.OrdinalIgnoreCase);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/Services/WindowsFeaturesService.cs` at line 131, The
current mapping sets isEnabled only when state.Equals("Enabled", ...), which
misses values like "Enabled with Payload Removed" or pending variants; update
the logic in WindowsFeaturesService.cs where the local variable isEnabled is set
from state to consider any state that starts with or contains "Enabled" (e.g.,
use state?.Trim().StartsWith("Enabled", StringComparison.OrdinalIgnoreCase) or
state?.IndexOf("Enabled", StringComparison.OrdinalIgnoreCase) >= 0) and ensure
you null-check state before calling methods so those variants are treated as
enabled.

Comment on lines +50 to +52
_cts?.Dispose();
_cts = new CancellationTokenSource();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -i 'WindowsFeaturesViewModel.cs|WindowsFeaturesView.xaml|ViewModelBase.cs' SysManager

echo "---- CTS replacement sites ----"
rg -n -C2 '_cts\?\.Dispose\(\)|new CancellationTokenSource\(\)|_cts\?\.Cancel\(\)' \
  SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs

echo "---- Command enablement / busy gating in view ----"
rg -n -C3 'ScanCommand|ToggleFeatureCommand|CancelCommand|IsEnabled|IsBusy|CanExecute' \
  SysManager/SysManager/Views/WindowsFeaturesView.xaml \
  SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs \
  SysManager/SysManager/ViewModels/ViewModelBase.cs

Repository: laurentiu021/SystemManager

Length of output: 13682


🏁 Script executed:

cat -n SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs | sed -n '77,88p'

Repository: laurentiu021/SystemManager

Length of output: 436


🏁 Script executed:

rg -n '\[RelayCommand\]|CanExecute|NotifyCanExecuteChanged' SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs | head -20

Repository: laurentiu021/SystemManager

Length of output: 137


🏁 Script executed:

cat -n SysManager/SysManager/ViewModels/ViewModelBase.cs

Repository: laurentiu021/SystemManager

Length of output: 1314


Add explicit Cancel() before disposing/replacing the CancellationTokenSource

At lines 50–51 and 99–100, _cts is disposed and replaced without an explicit Cancel() call. This creates a concurrency risk: if ToggleFeatureAsync is invoked while ScanAsync is running, the new CancellationTokenSource assignment invalidates the cancellation token held by the in-flight ScanAsync operation, potentially allowing stale work to continue undetected.

Proposed fix
-        _cts?.Dispose();
+        _cts?.Cancel();
+        _cts?.Dispose();
         _cts = new CancellationTokenSource();

Apply the same fix at lines 99–100.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_cts?.Dispose();
_cts = new CancellationTokenSource();
_cts?.Cancel();
_cts?.Dispose();
_cts = new CancellationTokenSource();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/ViewModels/WindowsFeaturesViewModel.cs` around lines 50
- 52, The code disposes and replaces the CancellationTokenSource field `_cts`
without calling `_cts.Cancel()`, which can leave in-flight `ScanAsync`
operations using an orphaned token; before calling `_cts.Dispose()` and
assigning a new `CancellationTokenSource`, call `_cts.Cancel()` (check for null)
to signal any running work, then dispose and replace it; apply this change in
both places where `_cts` is replaced (the existing block around
`_cts?.Dispose(); _cts = new CancellationTokenSource();` and the other
replacement near the same pattern) so `ToggleFeatureAsync`/`ScanAsync`
interactions are properly cancelled.

Comment on lines +45 to +52
<Border Background="#2D1F1F" CornerRadius="4" Padding="6,2" Margin="4,0"
Visibility="{Binding PendingReboot, Converter={StaticResource BoolToVis}}">
<TextBlock Text="⚠ Reboot pending" FontSize="11" Foreground="#F59E0B"/>
</Border>
<Border Background="#1F2D1F" CornerRadius="4" Padding="6,2" Margin="4,0"
Visibility="{Binding IsElevated, Converter={StaticResource BoolToVis}}">
<TextBlock Text="✓ Administrator" FontSize="11" Foreground="#4ADE80"/>
</Border>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid emoji-only status cues in badge text.

Line 47 and Line 51 include emoji markers (, ) in user-facing status labels; plain text (and optional icon controls) is more accessible and consistent.

Suggested tweak
- <TextBlock Text="⚠ Reboot pending" FontSize="11" Foreground="#F59E0B"/>
+ <TextBlock Text="Reboot pending" FontSize="11" Foreground="#F59E0B"/>

- <TextBlock Text="✓ Administrator" FontSize="11" Foreground="#4ADE80"/>
+ <TextBlock Text="Administrator" FontSize="11" Foreground="#4ADE80"/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/Views/WindowsFeaturesView.xaml` around lines 45 - 52,
Replace the emoji-only status markers in the two TextBlock elements so they use
plain, accessible labels (and optional icon controls) instead of leading emoji;
specifically update the TextBlocks that are inside the Border elements bound to
PendingReboot and IsElevated (the TextBlocks currently with Text="⚠ Reboot
pending" and Text="✓ Administrator") to use descriptive plain text like "Reboot
pending" and "Administrator" and, if an icon is desired, use an Image/Icon
control or an accessible glyph with AutomationProperties.Name set, ensuring the
PendingReboot and IsElevated bindings remain unchanged.

@laurentiu021
laurentiu021 merged commit 0f28b8c into main May 13, 2026
5 checks passed
@laurentiu021
laurentiu021 deleted the feat/windows-features branch May 13, 2026 08:13
laurentiu021 added a commit that referenced this pull request May 22, 2026
## Summary

SFC and DISM auto-relaunched the application with admin privileges
without asking the user first. This is a security concern — the user
must always be in control of privilege elevation.

## Changes

### CleanupViewModel.cs
- **RunSfcAsync**: Replaced silent auto-elevation with a Yes/No
MessageBox confirmation dialog. If the user declines, the operation is
cancelled with a clear status message.
- **RunDismAsync**: Same pattern — explicit consent required before
elevation.

## Security impact
- Users are no longer surprised by UAC prompts or unexpected app
restarts
- Declining elevation gracefully cancels the operation instead of
leaving the app in an undefined state

## Testing
- Build: 0 errors
- When not elevated + user clicks Yes: app restarts with admin (existing
behavior, now with consent)
- When not elevated + user clicks No: operation cancelled, status
message shown
- When already elevated: SFC/DISM runs normally (no dialog shown)

Closes #264

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
laurentiu021 added a commit that referenced this pull request May 22, 2026
- Add WindowsFeature model with category classification
- Add WindowsFeaturesService wrapping Get-WindowsOptionalFeature PowerShell
- Add WindowsFeaturesViewModel with scan, toggle, filter, admin check
- Add WindowsFeaturesView.xaml with DataGrid, category/state/toggle columns
- Replace WipWindowsFeatures placeholder with real implementation
- Register WindowsFeaturesService and VM in DI container
- Add 10 unit tests (ParseFeatureList, CategorizeFeature, HumanizeName, VM state)
- Update README: remove ⚙️ from Windows Features, add feature description
- Update CHANGELOG with v0.46.0 entry

Closes #5

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement]: System ΓÇö Windows optional features toggle

3 participants