Skip to content

feat: install Windows Update via WUA COM API (replaces PSWindowsUpdate)#611

Merged
laurentiu021 merged 3 commits into
mainfrom
feat/wua-com-api-install
Jun 3, 2026
Merged

feat: install Windows Update via WUA COM API (replaces PSWindowsUpdate)#611
laurentiu021 merged 3 commits into
mainfrom
feat/wua-com-api-install

Conversation

@laurentiu021
Copy link
Copy Markdown
Owner

@laurentiu021 laurentiu021 commented Jun 3, 2026

Summary

Reproduced live in 1.17.4: select 16 driver updates, click Install — UI shows "Installed 16", no real install happens, re-scan returns the same 16. Root cause investigated end-to-end: PSWindowsUpdate's Install-WindowsUpdate filters out optional driver updates client-side, even when the underlying Windows Update Agent COM API can install them perfectly. Verified with a manual Microsoft.Update.Session install of a single Dell Monitor driver — succeeded with ResultCode=2 while every PSWindowsUpdate variant (KB, Title, UpdateID, pipe-based) returned Installed [0].

This PR migrates the scan + install paths to direct WUA COM API calls. PSWindowsUpdate is kept only for the History view.

What changes

  • WindowsUpdateService — new service wrapping Microsoft.Update.Session. Handles scan (IsInstalled=0), download, EULA acceptance, install, reboot detection. Exposes a Log event for live console streaming.
  • WindowsUpdateViewModelListUpdatesAsync and InstallUpdatesAsync now call the new service. Per-row Status updated as install progresses (Pending…Downloading…Installing…Installed / Installed (reboot required) / Failed / Not applied). Aggregate report shows real counts.
  • Live console — real-time per-update events (Connecting → Downloading → Installing → ✓ Installed) instead of PSWindowsUpdate's noisy 16x repeated pre/post search.
  • Status column — widened to 200px with tooltip for messages like "Installed (reboot required)".
  • Console panel — fixed 240px height (no more auto-resize stealing grid space), removed redundant Card+Expander wrapper that produced two stacked headers.
  • Ping / Traceroute — removed the redundant live console panel. Both already display data graphically; the console was redundant and noisy.
  • KB column header — tooltip explaining the abbreviation, since not all updates have a KB (drivers, firmware, Defender Definitions).
  • Categorization — WUA Categories collection is the primary signal (authoritative), title heuristics as fallback. Pills colored per category.

Files

  • SysManager/Services/WindowsUpdateService.cs (new)
  • SysManager/ViewModels/WindowsUpdateViewModel.cs (rewritten install/scan, kept history)
  • SysManager/ViewModels/PingViewModel.cs (removed Console)
  • SysManager/ViewModels/TracerouteViewModel.cs (removed Console)
  • SysManager/Models/UpdateEntry.cs (added UpdateId property)
  • SysManager/ServiceRegistration.cs, MainWindowViewModel.cs (DI)
  • SysManager/Views/WindowsUpdateView.xaml, PingView.xaml, TracerouteView.xaml
  • SysManager.Tests/WindowsUpdateViewModelTests.cs (11 new tests for ClassifyCategory + FormatSize; removed obsolete tests)
  • CHANGELOG.md, README.md, csproj version → 1.17.5

Test plan

  • dotnet build -c Release SysManager.csproj — 0 errors
  • dotnet build -c Release SysManager.Tests.csproj — 0 errors
  • Manual: list + install 16 drivers via SysManager elevated — all installed successfully (verified in Settings → Update history)
  • Manual: re-scan after install — list shrunk to remaining drivers
  • Manual: live output streams real per-update progress
  • Live PowerShell repro of the COM API install path (single Dell Monitor driver, ResultCode=2 (Succeeded))
  • CI green on this PR

Summary by CodeRabbit

Release Notes v1.17.5

  • New Features

    • Windows Update interface now displays real-time per-update status progression with unified scanning and categorized updates.
    • Update categories displayed as styled pills for better visual clarity.
    • KB column enhanced with tooltips explaining Microsoft Knowledge Base references.
  • Improvements

    • Windows Update status column widened with improved visibility and tooltips.
    • Removed redundant live output panels from Ping and Traceroute views.
    • Streamlined Windows Update history view integration.
  • Bug Fixes

    • Enhanced Windows Update agent stability and per-update installation tracking with accurate status reporting.

Review Change Stack

PSWindowsUpdate's Install-WindowsUpdate filters out optional driver
updates client-side even when the underlying COM API can install them.
On a freshly-updated Windows 11 system, the only updates ever offered
are optional drivers/firmware — and PSWindowsUpdate would scan, find 20,
post-search filter to 0, and report "Installed 0" while SysManager's UI
falsely claimed success.

Switch the install path to direct Microsoft.Update.Session COM calls.
Live, real per-update progress streams to the console:

  Connecting to Windows Update…
  [1/N] HP Inc. SoftwareComponent Driver Update (4.8.130.0)
    Downloading…
    Installing…
    ✓ Installed

The new WindowsUpdateService also handles scan (IsInstalled=0), EULA
acceptance, reboot detection, and per-update categorization (Security,
Cumulative, Defender, Driver, Servicing, .NET, Feature upgrade, Hidden).
Categories come from WUA's own Categories collection where available,
title heuristics as fallback.

PSWindowsUpdate is kept only for the History view; install no longer
depends on it.

UI cleanup:
- Status column widened to 200px with tooltip for long messages like
  "Installed (reboot required)"
- Live output panel: fixed 240px, no auto-resize that stole grid space
- Removed redundant Card+Expander wrapper around ConsoleView (left the
  panel with two stacked headers)
- Removed live output from Ping and Traceroute (graphical chart and hops
  grid are sufficient; the console was redundant and noisy)
- KB column header tooltip explains the abbreviation since drivers,
  firmware, Defender Definitions etc. legitimately have no KB

Tests: 11 new unit tests for ClassifyCategory + FormatSize. Removed the
obsolete ParseInstallResults / StripAndSplitKb tests (no longer needed
with COM API).

Closes the silent-success bug surfaced during 1.17.4 testing where 16
selected drivers reported "Installed" but were never actually applied.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Warning

Rate limit exceeded

@laurentiu021 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 23 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3739fabd-6337-4510-a00e-30eedfc74e82

📥 Commits

Reviewing files that changed from the base of the PR and between a68746a and 2d133da.

📒 Files selected for processing (3)
  • SysManager/SysManager.Tests/WindowsUpdateViewModelTests.cs
  • SysManager/SysManager/Services/WindowsUpdateService.cs
  • SysManager/SysManager/ViewModels/WindowsUpdateViewModel.cs
📝 Walkthrough

Walkthrough

This PR migrates the Windows Update feature from PowerShell-based operations to Windows Update Agent COM API integration, refactors the ViewModel and UI accordingly, removes redundant console outputs from Ping/Traceroute views, and releases version 1.17.5.

Changes

Windows Update COM API Migration

Layer / File(s) Summary
Model and DI infrastructure
SysManager/Models/UpdateEntry.cs, SysManager/ServiceRegistration.cs
UpdateEntry gains UpdateId property; WindowsUpdateService registered as singleton in DI container.
WindowsUpdateService COM wrapper with unit tests
SysManager/Services/WindowsUpdateService.cs, SysManager.Tests/WindowsUpdateViewModelTests.cs
WindowsUpdateService wraps WUA COM API with ScanAsync (query not-installed updates) and InstallAsync (download/install selections); includes helpers for category classification (title keywords + COM category inspection), KB ID extraction, and byte-size formatting; unit tests validate category mapping and size formatting.
WindowsUpdateViewModel refactoring and wiring
SysManager/ViewModels/WindowsUpdateViewModel.cs, SysManager/ViewModels/MainWindowViewModel.cs
WindowsUpdateViewModel now depends on injected WindowsUpdateService and routes scan/install operations through service methods instead of PowerShell scripts; constructor wires service logging to console; ListUpdatesAsync calls ScanAsync and sorts by title; InstallUpdatesAsync calls InstallAsync and handles per-entry status/COMException; test/designer constructor in MainWindowViewModel instantiates service.
WindowsUpdate view UI redesign
SysManager/Views/WindowsUpdateView.xaml
Expanded header description with KB semantics guidance; KB column enhanced with tooltip; Status column widened with tooltip binding; Category column replaced with templated bordered pills using per-category background/border/foreground DataTriggers; console output changed from collapsible Expander to fixed-height ConsoleView.
Ping and Traceroute console cleanup
SysManager/ViewModels/PingViewModel.cs, SysManager/ViewModels/TracerouteViewModel.cs, SysManager/Views/PingView.xaml, SysManager/Views/TracerouteView.xaml
Removed Console property and event-subscription logic from both ViewModels; removed console append calls during operations; adjusted grid row definitions and removed console UI sections from both XAML views.
Version and release documentation
SysManager/SysManager.csproj, CHANGELOG.md, README.md
Version incremented to 1.17.5; CHANGELOG documents Windows Update COM integration, per-update status tracking, UI improvements, and console cleanup; README updated to describe COM-based flow with PSWindowsUpdate marked optional for history.

Sequence Diagram

sequenceDiagram
  participant User
  participant VM as WindowsUpdateViewModel
  participant Svc as WindowsUpdateService
  participant WUA as WUA COM API
  
  User->>VM: List Updates
  VM->>Svc: ScanAsync
  Svc->>WUA: Create session, search
  WUA-->>Svc: Update objects
  Svc->>Svc: Map to UpdateEntry
  Svc-->>VM: Update list
  VM->>VM: Sort by title
  
  User->>VM: Install selected
  VM->>Svc: InstallAsync
  Svc->>WUA: Re-scan live state
  Svc->>WUA: Download updates
  Svc->>WUA: Install via COM
  Svc->>Svc: Track per-entry status
  Svc-->>VM: InstallReport
  VM->>VM: Update UI and toast
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • laurentiu021/SystemManager#609: The main PR replaces #609's PowerShell/JSON WindowsUpdateViewModel install pipeline (including ParseInstallResults) with the new COM-based WindowsUpdateService and updates the view/test code accordingly.
  • laurentiu021/SystemManager#473: Both PRs update the Windows Update tab's per-update install selection flow in WindowsUpdateViewModel, but the main PR replaces #473's KB-validated Install-WindowsUpdate checkbox install path with the new WindowsUpdateService COM-based scan/install driving per-entry status.

Poem

🐰 From PowerShell scripts to COM's bright call,
Updates now dance through Agent's hall,
Categories bloom with styled design,
Ping and Traceroute console lines recline,
Version one-seventeen-five takes the floor!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 accurately summarizes the primary change: replacing PSWindowsUpdate with direct WUA COM API integration for installing Windows updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wua-com-api-install

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov-commenter
Copy link
Copy Markdown

⚠️ JUnit XML file not found

The CLI was unable to find any JUnit XML files to upload.
For more help, visit our troubleshooting guide.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
SysManager/SysManager/Services/WindowsUpdateService.cs (1)

126-144: ⚖️ Poor tradeoff

No timeout on download/install operations.

The download (line 131) and install (line 158) operations call synchronous COM methods without any timeout. If the WUA service hangs or a download stalls, the operation will block indefinitely, and cancellation token checks only occur between operations, not during them. Consider documenting this limitation or implementing a timeout wrapper.

Also applies to: 152-176

🤖 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/WindowsUpdateService.cs` around lines 126 -
144, The download and install calls (dl.Download() and installer.Install()) in
WindowsUpdateService are synchronous COM operations that can block indefinitely;
wrap these calls in a cancellable/timeout-aware Task (e.g., Task.Run with a
timeout and the provided CancellationToken) so the method can abort a hung
operation, ensure Marshal.FinalReleaseComObject is called on
dl/dlResult/installer even on timeout/exception, and set the entry.Status/failed
counter and emit a clear timeout message when the operation times out; locate
dl.Download() and installer.Install() in the update loop and replace them with
this timeout-wrapper pattern or use WUA async APIs if available.
🤖 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 `@SysManager/SysManager/Services/WindowsUpdateService.cs`:
- Around line 44-61: The COM objects (updates, result, searcher, session)
created in the scan path can leak if an exception is thrown inside the for-loop;
wrap the whole COM interaction in a try/finally (or try/catch/finally) around
the code that accesses updates and builds the list (the block that uses
result.Updates, updates.Item(i), MapToEntry, etc.) and move the
Marshal.FinalReleaseComObject calls into the finally block so each COM object is
released even on exceptions (check for null before releasing and swallow/log any
exceptions during release to avoid hiding the original error).

---

Nitpick comments:
In `@SysManager/SysManager/Services/WindowsUpdateService.cs`:
- Around line 126-144: The download and install calls (dl.Download() and
installer.Install()) in WindowsUpdateService are synchronous COM operations that
can block indefinitely; wrap these calls in a cancellable/timeout-aware Task
(e.g., Task.Run with a timeout and the provided CancellationToken) so the method
can abort a hung operation, ensure Marshal.FinalReleaseComObject is called on
dl/dlResult/installer even on timeout/exception, and set the entry.Status/failed
counter and emit a clear timeout message when the operation times out; locate
dl.Download() and installer.Install() in the update loop and replace them with
this timeout-wrapper pattern or use WUA async APIs if available.
🪄 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: 3ab9350b-d861-46cf-844c-846c6c86eae8

📥 Commits

Reviewing files that changed from the base of the PR and between 2c3f935 and a68746a.

📒 Files selected for processing (14)
  • CHANGELOG.md
  • README.md
  • SysManager/SysManager.Tests/WindowsUpdateViewModelTests.cs
  • SysManager/SysManager/Models/UpdateEntry.cs
  • SysManager/SysManager/ServiceRegistration.cs
  • SysManager/SysManager/Services/WindowsUpdateService.cs
  • SysManager/SysManager/SysManager.csproj
  • SysManager/SysManager/ViewModels/MainWindowViewModel.cs
  • SysManager/SysManager/ViewModels/PingViewModel.cs
  • SysManager/SysManager/ViewModels/TracerouteViewModel.cs
  • SysManager/SysManager/ViewModels/WindowsUpdateViewModel.cs
  • SysManager/SysManager/Views/PingView.xaml
  • SysManager/SysManager/Views/TracerouteView.xaml
  • SysManager/SysManager/Views/WindowsUpdateView.xaml
💤 Files with no reviewable changes (4)
  • SysManager/SysManager/Views/PingView.xaml
  • SysManager/SysManager/ViewModels/PingViewModel.cs
  • SysManager/SysManager/Views/TracerouteView.xaml
  • SysManager/SysManager/ViewModels/TracerouteViewModel.cs
📜 Review details
🔇 Additional comments (10)
SysManager/SysManager/SysManager.csproj (1)

13-15: LGTM!

CHANGELOG.md (1)

9-26: LGTM!

README.md (1)

122-143: LGTM!

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

23-23: LGTM!

SysManager/SysManager/ServiceRegistration.cs (1)

62-62: LGTM!

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

70-201: LGTM!

Also applies to: 203-213, 215-237, 239-255, 257-300, 302-313

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

18-18: LGTM!

Also applies to: 208-238

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

19-19: LGTM!

Also applies to: 33-48, 63-63, 136-171, 262-313

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

169-169: LGTM!

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

34-35: LGTM!

Also applies to: 154-167, 180-190, 203-285, 290-295

Comment on lines +44 to +61
var updates = result.Updates;
var count = (int)updates.Count;
Emit($"Found {count} update(s).");

var list = new List<UpdateEntry>(count);
for (int i = 0; i < count; i++)
{
ct.ThrowIfCancellationRequested();
var u = updates.Item(i);
list.Add(MapToEntry(u));
Marshal.FinalReleaseComObject(u);
}

Marshal.FinalReleaseComObject(updates);
Marshal.FinalReleaseComObject(result);
Marshal.FinalReleaseComObject(searcher);
Marshal.FinalReleaseComObject(session);
return list;
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

COM object leak risk on exception path.

If an exception occurs during the loop (lines 49-55), the updates collection, result, searcher, and session COM objects won't be released. Consider wrapping the entire COM interaction in a try/finally block similar to InstallAsync.

🛠️ Proposed fix
     public Task<IReadOnlyList<UpdateEntry>> ScanAsync(CancellationToken ct = default) =>
         Task.Run<IReadOnlyList<UpdateEntry>>(() =>
         {
             ct.ThrowIfCancellationRequested();
             Emit("Connecting to Windows Update…");
             var session = CreateSession();
             var searcher = session.CreateUpdateSearcher();
             searcher.IncludePotentiallySupersededUpdates = false;
+            dynamic? result = null;
+            dynamic? updates = null;
 
-            // "IsInstalled=0" returns everything not yet installed,
-            // including optional drivers and feature upgrades.
-            var result = searcher.Search("IsInstalled=0");
-            ct.ThrowIfCancellationRequested();
-
-            var updates = result.Updates;
-            var count = (int)updates.Count;
-            Emit($"Found {count} update(s).");
-
-            var list = new List<UpdateEntry>(count);
-            for (int i = 0; i < count; i++)
+            try
             {
-                ct.ThrowIfCancellationRequested();
-                var u = updates.Item(i);
-                list.Add(MapToEntry(u));
-                Marshal.FinalReleaseComObject(u);
+                result = searcher.Search("IsInstalled=0");
+                ct.ThrowIfCancellationRequested();
+
+                updates = result.Updates;
+                var count = (int)updates.Count;
+                Emit($"Found {count} update(s).");
+
+                var list = new List<UpdateEntry>(count);
+                for (int i = 0; i < count; i++)
+                {
+                    ct.ThrowIfCancellationRequested();
+                    var u = updates.Item(i);
+                    list.Add(MapToEntry(u));
+                    Marshal.FinalReleaseComObject(u);
+                }
+                return list;
+            }
+            finally
+            {
+                if (updates is not null) Marshal.FinalReleaseComObject(updates);
+                if (result is not null) Marshal.FinalReleaseComObject(result);
+                Marshal.FinalReleaseComObject(searcher);
+                Marshal.FinalReleaseComObject(session);
             }
-
-            Marshal.FinalReleaseComObject(updates);
-            Marshal.FinalReleaseComObject(result);
-            Marshal.FinalReleaseComObject(searcher);
-            Marshal.FinalReleaseComObject(session);
-            return list;
         }, ct);
🤖 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/WindowsUpdateService.cs` around lines 44 - 61,
The COM objects (updates, result, searcher, session) created in the scan path
can leak if an exception is thrown inside the for-loop; wrap the whole COM
interaction in a try/finally (or try/catch/finally) around the code that
accesses updates and builds the list (the block that uses result.Updates,
updates.Item(i), MapToEntry, etc.) and move the Marshal.FinalReleaseComObject
calls into the finally block so each COM object is released even on exceptions
(check for null before releasing and swallow/log any exceptions during release
to avoid hiding the original error).


try
{
if (!(bool)u.IsDownloaded)
}
}

if (!(bool)u.EulaAccepted)
inst.Updates = coll;
var iResult = inst.Install();
var iCode = (int)iResult.ResultCode;
bool needsReboot = (bool)iResult.RebootRequired;
Comment thread SysManager/SysManager/Services/WindowsUpdateService.cs Fixed
Title = title,
KB = kb,
Size = FormatSize(size),
UpdateId = (string)u.Identity.UpdateID,
var kb = kbList.Count > 0 ? "KB" + string.Join(",", kbList) : string.Empty;
long size = 0;
try { size = (long)(decimal)u.MaxDownloadSize; } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { }
catch (COMException) { }
if (!string.IsNullOrWhiteSpace(id)) list.Add(id);
}
}
catch (COMException) { }
}
}
catch (COMException) { }
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { }
}
Marshal.FinalReleaseComObject(cats);
}
catch (COMException) { }
Marshal.FinalReleaseComObject(cats);
}
catch (COMException) { }
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { }
var kbList = ExtractKbIds(u);
var kb = kbList.Count > 0 ? "KB" + string.Join(",", kbList) : string.Empty;
long size = 0;
try { size = (long)(decimal)u.MaxDownloadSize; }
var kb = kbList.Count > 0 ? "KB" + string.Join(",", kbList) : string.Empty;
long size = 0;
try { size = (long)(decimal)u.MaxDownloadSize; }
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { }
…ation test

- WindowsUpdateViewModel no longer kicks off CheckModuleAsync at construction.
  PSWindowsUpdate is needed only for the History view, so probe it lazily
  there. This keeps the constructor side-effect-free and prevents IsBusy
  from racing with construction-time test assertions on faster CI runners.
- ClassifyCategory test: replace the "Intel Corporation - Display - ..."
  case with "HP Firmware Driver Update (...)". The Intel string contains
  neither "Driver" nor "Firmware" — the title-only path correctly returns
  "Update". On a real system the COM Categories collection classifies it
  as Driver; the unit test (which doesn't pass a COM object) cannot.
@laurentiu021 laurentiu021 merged commit 9be5cf8 into main Jun 3, 2026
4 of 5 checks passed
@laurentiu021 laurentiu021 deleted the feat/wua-com-api-install branch June 3, 2026 11:38
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.

3 participants