Skip to content

fix(harness): sessions from the desktop processes' owners, matched by SID - #10

Merged
fadwen merged 1 commit into
mainfrom
fix/harness-session-by-sid
Oct 6, 2026
Merged

fadwen merged 1 commit into
mainfrom
fix/harness-session-by-sid

Conversation

@fadwen

@fadwen fadwen commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Summary

-Credential on the harness commands decided between an interactive task and a stored-password task by parsing query user. Windows Home editions do not ship query.exe, so every run there fell back to the stored-password task, and the tool's output is localized, so the parse depended on the device's language. The session list now comes from the owners of each desktop's explorer.exe and sihost.exe through CIM, and the account is matched by its SID.

Follows #6, which resolved the credential's name to the account Windows means but still matched the session on the resulting name.

Changes

  • Get-IslLogonSession. Lists one session per desktop user from Win32_Process (explorer.exe, or sihost.exe while the desktop is still starting), with the owner's name and domain from GetOwner, the SID from GetOwnerSid, and the session id. A process whose owner cannot be read is left out. Reading another account's process owner needs an elevated session, which the credential launch needs anyway.
  • Invoke-IslProcess. Matches the session by SID when Resolve-IslAccount resolves the credential's name, by the owner's name as text otherwise.
  • Get-IslQueryUserOutput removed with its only caller.
  • Tests. Get-IslLogonSession over mocked CIM: one session per user from several shell processes, a session with sihost.exe alone, an unreadable owner left out, no desktop at all, and the real machine for shape. Launcher tests carry the new session shape (Sid, Domain).
  • Documentation. Findings ("The harness as another account") records the measurement; changelog under Unreleased.

Verification

  • Unit and integration suites: 927 pass on PowerShell 7.6.6 (8 skipped: elevation, lab credential); 875 pass on Windows PowerShell 5.1 for the unit suites and two integration files (33 skipped). PSScriptAnalyzer (Error and Warning) is clean; no line over 115 characters.
  • Windows 11 Home (no query.exe): Get-IslLogonSession lists the console session with its SID, where the previous version returned nothing.
  • Joined lab device, VM 125, the Entra test user signed in, the module run as SYSTEM: Get-IslLogonSession listed AzureAD\IslVerylongdisplayna, SID S-1-12-1-...-805488699, session 2, the SID the sign-in name resolves to; -Credential with the sign-in name, AzureAD\<sign-in name> and the Windows name each ran the script inside session 2 with interactive=True, and left no task and no run folder behind.

Notes

… SID

-Credential parsed 'query user' to tell whether the account holds a session. Windows Home editions do not ship query.exe, so every run there fell back to the stored-password task, and the tool prints localized text. The session list now comes from the owners of each desktop's explorer.exe and sihost.exe through CIM, with the owner's SID, and the account is matched by the SID its name resolves to, by the owner's name as text otherwise. Verified on a Home machine and on the joined lab device with the Entra test user signed in.

@fadwen fadwen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Notes on the lines whose reason the diff does not show.

$filter = "Name='explorer.exe' OR Name='sihost.exe'"
$shells = @(Get-CimInstance -ClassName Win32_Process -Filter $filter -ErrorAction SilentlyContinue)
$seen = @{}
foreach ($shell in ($shells | Sort-Object -Property SessionId, Name)) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

CIM returns processes in no fixed order. Sorted so the output order is the same on both hosts and, where a session has both processes, the explorer.exe row is the one kept by the check below.

$owner = Invoke-CimMethod -InputObject $shell -MethodName GetOwner -ErrorAction SilentlyContinue
$sid = (Invoke-CimMethod -InputObject $shell -MethodName GetOwnerSid -ErrorAction SilentlyContinue).Sid
if (-not $sid -or -not $owner.User) { continue }
$key = "$($shell.SessionId)|$sid"

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

One session can hold several of these processes: sihost.exe next to explorer.exe, and a second explorer.exe when a folder window runs as its own process. One row per session and owner is what the caller counts.

else { $userName }
$sessions = @(Get-IslLogonSession | Where-Object { $_.UserName -eq $account })
$sessions = @(Get-IslLogonSession | Where-Object {
if ($resolved) { $_.Sid -eq $resolved.Sid } else { $_.UserName -eq $account }

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The text match is the path for a name Windows cannot translate, where Resolve-IslAccount returns nothing. It keeps the behaviour from before #6 there, and the scheduler then reports the real error for the name itself.

' isl-user 3 Disc 1:23 9/28/2026 1:02 AM'
It 'lists one session per desktop user, from the owner of its shell processes' {
$sessions = Get-Session @(
(New-Shell 'sihost.exe' 1 101), (New-Shell 'explorer.exe' 1 100), (New-Shell 'explorer.exe' 2 200)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

sihost.exe is listed before explorer.exe, and with the higher process id, on purpose: the result must not depend on the order CIM hands the processes back.

@fadwen
fadwen added this pull request to stack #15 October 6, 2026 06:46
@fadwen
fadwen merged commit ddf5239 into main Oct 6, 2026
4 checks passed
@fadwen
fadwen deleted the fix/harness-session-by-sid branch October 6, 2026 06:52
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.

1 participant