TL;DR
Microsoft 365 Apps delivered as Horizon published applications failed to sign in with Something went wrong [4nsvw]. The cause is Horizon’s app-session shell replacement: with AppSessionShellReplacement = horizon-unity-shell.exe, the session runs without Explorer, and the Web Account Manager (WAM) broker has nothing to host it. It hits published apps in general: Horizon 8 RDS hosts on Server 2022 and Windows 11 multi-session in Horizon Cloud alike.
Re-registering the broker package and starting ShellAppRuntime.exe at logon only treated the symptom; on Server 2022 the latter crashed over 100 times a day on one host. Removing the registry value fixed it: shell crashes fell from 109 to about one a day.
The setup and the symptom
Office sign-in failed only in published-app sessions; the same user in a full desktop on the same host was already signed in. We saw it on both our Horizon platforms.
| Component | Detail |
|---|---|
| Platforms | Omnissa Horizon 8 on-prem pod; Horizon Cloud Next-Gen on Azure |
| Session hosts | Windows Server 2022 RDS farm (build 20348); Windows 11 multi-session |
| Delivery | Published applications |
| Identity | Entra ID, hybrid-joined on-prem hosts |
| Profile and logon | Omnissa Dynamic Environment Manager (DEM) |
| Apps | Microsoft 365 Apps, Shared Computer Activation |
The error dialog showed tag 4nsvw and code 2147746132. In hex that is 0x80040154, REGDB_E_CLASSNOTREG: Office asked COM for the WAM broker and nothing answered. It is not a token, Conditional Access or hybrid-join problem.
'0x{0:X}' -f 2147746132 # 0x80040154
What we tried first
Two logon-time fixes treated the symptom, and neither touched the cause.
Re-register the broker package. If the WAM plugin is not registered for the user, Office gets exactly this 0x80040154. A DEM logon script re-registered it when it was missing (the script is in The fix below). It is harmless and worth keeping, but the package was already registered for the affected users, so the error stayed.
Start ShellAppRuntime.exe at logon. This process hosts the broker plugin when no Explorer is around, so we launched it with a DEM logon task. It seemed to work for a day. Then the Application log on one Server 2022 host showed:
- Event 1000:
ShellAppRuntime.exe10.0.20348.3692 faulting intwinui.pcshell.dll10.0.20348.5386, exception0x80270233. - Event 1002, one second later: The shell stopped unexpectedly and explorer.exe was restarted.
- 109 of these pairs in a single working day.
Winlogon treated the crashing process as the session shell and replaced it with Explorer. Some sessions caught the broker mid-handover: System event 10010 shows Microsoft.AAD.BrokerPlugin…BackgroundGetTokenTask failing to register with DCOM, one second after a crash, and Office showed [4nsvw] again.
Note the version gap between the executable and the shell DLL it loads. My guess, not confirmed, is that this binary is not kept in step with cumulative updates on Server 2022. Launched by hand later in a session, it simply exits with code 2.
Both were patches for a missing shell. The real question was why the shell was missing.
How to diagnose it
The useful evidence sat in four places, and the popup itself told us almost nothing.
- AAD operational log, filtered by user. Each event carries the user’s SID, so you can isolate one person:
$u = 'DOMAIN\user' Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-AAD/Operational'; StartTime=(Get-Date).Date} | ? { try { $_.UserId.Translate([Security.Principal.NTAccount]).Value -eq $u } catch { $false } } | ? { $_.Message -notmatch '/cortana|0x4AA50081|0xCAA9001F' } | Sort TimeCreated | Select TimeCreated, Id, LevelDisplayName, Message | fl
No token request at all from Office (clientd3590ed6-…) at the time of the error means the call never reached the broker. - DCOM timeouts in the System log. Event 10010 naming
Microsoft.AAD.BrokerPluginis the broker failing to start. These events have no user, so correlate by time. - Who started Explorer in each session. One WMI query, joined in memory:
$all = Get-CimInstance Win32_Process -Property ProcessId,ParentProcessId,Name,CommandLine,CreationDate,SessionId $byPid = @{}; $all | % { $byPid[[int]$_.ProcessId] = $_ } $all | ? Name -eq 'explorer.exe' | % { $p = $byPid[[int]$_.ParentProcessId] [pscustomobject]@{ Session=$_.SessionId; Started=$_.CreationDate Parent = if ($p -and $p.CreationDate -lt $_.CreationDate) { $p.Name } else { '<exited>' } } } | Sort Session | ft - Crashes in the Application log. Events 1000 and 1002 for
ShellAppRuntime.exe, grouped by day.
The Explorer parents split the sessions into three groups, and only one is healthy:
| Explorer started by | What it means |
|---|---|
<exited> (userinit) | Full desktop; Explorer is the real shell and WAM works |
OneDrive.exe /background | OneDrive pulls Explorer into an app session as a side effect |
winlogon.exe | Shell restart after a crash; every one matched a ShellAppRuntime crash to the second |
Some log noise looks alarming but is normal:
| Code | Meaning |
|---|---|
0xCAA9001F | Integrated Windows auth only in federated tenants; WAM falls back |
AADSTS500011 on /cortana | Windows Search asking for a resource the tenant lacks |
0x4AA50081 | Informational warning when loading the account |
AADSTS50076 | MFA required; check whose account it is before chasing it |
One trap: Task Scheduler’s LastTaskResult is the program’s exit code, not a launch error. A 2 from ShellAppRuntime.exe looked like file not found until the same test under a healthy user also returned 2.
The real cause: Horizon replaces the shell
The Horizon Agent was configured to run its own shell in published-app sessions:
Get-ItemProperty 'HKLM:\SOFTWARE\Omnissa\Horizon\Agent' -Name AppSessionShellReplacement
# AppSessionShellReplacement : horizon-unity-shell.exe
With that value set, a published-app session starts horizon-unity-shell.exe instead of Explorer. That keeps the session light, but WAM depends on the Windows shell being there. Without it, Office’s request for the broker fails with 0x80040154.
It is not specific to RDSH or to on-prem. Windows 11 multi-session hosts publishing apps from Horizon Cloud Next-Gen behave the same way: same value, same error, same fix. We had already removed the value there with a Group Policy Preferences item, but that GPO was linked to the cloud OU, so the on-prem RDS farm never got it.
I found no public Omnissa documentation for AppSessionShellReplacement. What it does here is inferred from its value and from the result of removing it.
The fix
Delete the value, drop the ShellAppRuntime logon task, reboot. Shell crashes on the test host fell from 109 in one day to one a day afterwards.
- Test on one host first, in drain mode:
reg export "HKLM\SOFTWARE\Omnissa\Horizon\Agent" C:\temp\horizon_agent_backup.reg /y Remove-ItemProperty 'HKLM:\SOFTWARE\Omnissa\Horizon\Agent' -Name AppSessionShellReplacement shutdown /r /t 0 - Make it stick with a GPP registry item, action Delete, linked to every OU holding Horizon hosts that publish apps, RDSH and Windows 11 multi-session alike. An agent upgrade can write the value back; the GPP removes it again on the next refresh.
- Remove any logon task or script that starts
ShellAppRuntime.exe. - Keep a logon script that re-registers the broker package per user only when it is missing or broken:
$p = Get-AppxPackage Microsoft.AAD.BrokerPlugin if (-not $p -or $p.Status -ne 'Ok') { Add-AppxPackage -Register "$env:windir\SystemApps\Microsoft.AAD.BrokerPlugin_cw5n1h2txyewy\Appxmanifest.xml" -DisableDevelopmentMode -ForceApplicationShutdown }
Leftover per-user cases. A week later one user on the fixed host was still asked to sign in, as if her PRT were ignored. The host was clean: no shell replacement, no crashes. A profile reset fixed it, so her broker cache was corrupt. Next time, try a targeted reset first, with the user logged off:
$prof = '<profile path>'; $ts = Get-Date -f yyyyMMddHHmm
"$prof\AppData\Local\Packages\Microsoft.AAD.BrokerPlugin_cw5n1h2txyewy",
"$prof\AppData\Local\Microsoft\TokenBroker",
"$prof\AppData\Local\Microsoft\IdentityCache",
"$prof\AppData\Local\Microsoft\OneAuth" | ? { Test-Path $_ } | % { Rename-Item $_ "$_.bak_$ts" }
reg load HKU\RESET "$prof\NTUSER.DAT"
reg delete "HKU\RESET\Software\Microsoft\Office\16.0\Common\Identity" /f
[gc]::Collect(); reg unload HKU\RESET
If DEM roams any of those folders or that registry key, exclude them. Otherwise the corrupt state comes back with the next logon.
Lessons and what Omnissa should change
A lightweight app-session shell and Microsoft’s WAM broker do not coexist in published-app sessions, on RDSH and Windows 11 multi-session alike, and nothing in the product warns you.
- Check the shell before chasing identity.
0x80040154behind [4nsvw] is a local COM failure, not Entra ID. - Patching a missing shell is not a fix. On Server 2022,
ShellAppRuntime.execrashed instead of helping. - Count crashes per day before declaring victory. The first day looked fixed; the Application log said otherwise.
- Compare like with like. An admin RDP desktop proves nothing about a published-app session.
What would have saved us a week:
- Document
AppSessionShellReplacement: values, default, and its effect on WAM and Microsoft 365 sign-in. - Expose it as a per-farm setting in the console, not a hidden agent value.
- Have the Horizon app-session shell host, or start on demand, what WAM needs; or warn when Microsoft 365 Apps are published with shell replacement on.
I have filed a feature request with Omnissa along these lines.
