Yes — the elevated shell keeps the session ID of the desktop it was launched from, so you can compare the account inside your process token with the account that owns that session. When the two differ, the script was elevated with someone else's credentials, and everything that follows the token — HKEY_CURRENT_USER, %USERPROFILE%, mapped drives — silently points at the wrong profile. This article shows a quick manual check, a scriptable check you can gate a script on, and an audit-log route for investigating incidents after the fact.
Why elevation can silently switch accounts
User Account Control gives every interactive administrator a split token at logon: a filtered token for everyday work, and a full token that is only attached after a UAC prompt is approved. Elevating yourself simply swaps in the other half of your own logon. But the UAC prompt also accepts a completely different set of credentials — the over-the-shoulder scenario, where a colleague or a service account approves the prompt. Windows then builds a brand-new token for that second account and runs your script with it, while the process stays inside the original desktop session.
The script still sees the same screen and session, yet its identity, its HKCU view, its profile paths, and its per-logon mapped drives all belong to whoever typed the password. That mismatch is what breaks installers that write per-user settings, scripts that touch the logged-on user's registry hive, and anything expecting the desktop user's environment.
A thirty-second manual check
Open the elevated console and run two commands:
whoami
qwinsta
whoami reports the account in your process token. qwinsta lists every session on the machine, and the USERNAME column shows who owns each one:
SESSIONNAME USERNAME ID STATE TYPE DEVICE
services 0 Disc
>console jdoe 1 Active
If the console line (or your rdp-tcp#n line over remote desktop) shows a different name than whoami, your elevated shell is running as another account.
A scriptable check you can gate on
The manual comparison translates directly into code: ask Terminal Services which user owns the session your process lives in, then compare it with your own token. The session ID never changes across UAC elevation, so this check is stable:
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public static class WtsSession
{
[DllImport("wtsapi32.dll")]
static extern bool WTSQuerySessionInformation(
IntPtr hServer, int sessionId, int infoClass,
out IntPtr pBuffer, out int bytesReturned);
[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pMemory);
const int WTSUserName = 5;
const int WTSDomainName = 7;
public static string GetSessionUser(int sessionId)
{
IntPtr buf; int len;
string domain = "", user = "";
if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WTSDomainName, out buf, out len))
{ domain = Marshal.PtrToStringAnsi(buf); WTSFreeMemory(buf); }
if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WTSUserName, out buf, out len))
{ user = Marshal.PtrToStringAnsi(buf); WTSFreeMemory(buf); }
return domain + "\\" + user;
}
}
'@
$me = [Security.Principal.WindowsIdentity]::GetCurrent().Name
$owner = [WtsSession]::GetSessionUser([Diagnostics.Process]::GetCurrent().SessionId)
if ($me -ieq $owner) {
'Same account - safe to continue.'
} else {
throw "Elevated as $me, but the desktop session belongs to $owner."
}
For a stricter comparison, translate the session owner's name into a SID and compare SIDs instead of strings; NTAccount/SecurityIdentifier translation handles local-versus-domain name collisions.
An alternative is to read the security descriptor of your process's window station: its DACL contains a per-user access-allowed ACE (an S-1-5-21-... SID) for the desktop owner, and elevation merely appends an Administrators group ACE. Extracting that SID and comparing it with your token SID also works, but you have to guess which ACE is the user ACE, so the WTS route above is simpler and less brittle.
Investigating after the fact with the security event log
If you need to know who elevated what — rather than gate a script — the Windows security log answers this in event ID 4624, provided success logon auditing was enabled beforehand. Every interactive logon of an administrator on a UAC-enabled system produces paired 4624 events, one with Elevated Token: Yes and one with No, tied together by the Logon ID and, on Windows 10 / Server 2016 and newer, the Linked Logon ID field. When someone approves a UAC prompt with different credentials, the log records a 4624 for that account with an elevated token, letting you correlate the elevated logon with the console session and see exactly which account was used.
Reading the security log requires administrative rights, and because auditing must be switched on before the event occurs, this is a forensics tool, not an in-script check.
Pitfalls and hardening
- Don't trust the window station's Owner field. It always reads
BUILTIN\Administrators, never the desktop user — use the DACL's per-user ACE or the WTS query instead. - Don't infer anything from group membership. Whether the token is an admin says nothing about which account owns the desktop; two different administrators produce the same "elevated: yes" result.
- Compare SIDs when you can. A local and a domain account can share a name; SIDs cannot collide.
- Fail fast. Put the comparison at the top of the script and exit with a message naming both accounts, rather than failing three steps later on a missing mapped drive.
- Re-map drives or use UNC paths. Mapped drives are per logon session; if the elevated context needs the user's drive, map it again inside the script or address the share directly.
- Load the right hive explicitly. If you must edit the desktop user's registry from a different elevated account, load their
NTUSER.DATunder a custom key instead of relying on HKCU.
Frequently Asked Questions
Does UAC elevation change the session ID?
No. The elevated process stays in the same session as the desktop; only the security token — and therefore the account — changes. That is exactly why session-based checks like the WTS query work.
Why can't I just check %USERPROFILE% or HKEY_CURRENT_USER?
Because both follow the token, not the session. They show the elevating account's profile — the very thing that breaks. Use them to confirm symptoms, not to identify the desktop owner.
Does the WTS check work over RDP?
Yes. The query uses your own process's session ID, so it behaves identically for console and remote sessions, returning whichever user is logged on to that session.
Do I need administrator rights to run these checks?
Not for the token and session comparisons — both read information your own process already has access to. Yes for the security event log, which also requires success logon auditing to have been enabled in advance.
Why compare SIDs instead of usernames?
Account names are only unique within their domain; a local account and a domain account can share a display name. SIDs such as S-1-5-21-... are unambiguous, so SID comparison avoids false "same user" results.
Can the script continue safely when the accounts differ?
Sometimes. If the script only touches machine-wide state, the mismatch is harmless — log a warning and continue. If it touches HKCU, profile paths, or the user's mapped drives, either re-run unelevated as the desktop user or perform those steps explicitly against that user's profile.