Problem Overview
On a Siemens WinCC 7 SCADA station that runs as a published Remote Desktop application on Windows Server (Terminal Server role) with the SIMATIC WinCC WebNavigator add-on, multiple operators can be logged on to the same WinCC Runtime simultaneously through separate RDP sessions. Each thin client (or operator workstation) opens its own RDP session, and each session runs its own Internet Explorer instance that points to the WebNavigator client.
The runtime must distinguish which Windows user is currently driving the picture so it can:
- Load the operator's specific area picture (e.g. infeed, modify, outfeed).
- Apply the correct WinCC user-rights profile (Operator, Maintenance, Administrator).
- Filter alarms, archives, and audit-trail entries per session.
- Suppress simultaneous control of the same motor or valve from two RDP sessions.
The default HMIRuntime.User property returns the WinCC user (Operator / Maintenance / Administrator), not the underlying Windows user account that opened the RDP session. Reading the Windows logon name requires either scripting, registry access, or a Windows API call.
WinCC 7 Terminal Services Architecture
Three independent authentication layers exist on a typical WinCC 7 Terminal Server deployment:
| Layer | Identity | Authoritative store | Read via |
|---|---|---|---|
| Windows session | ThinClient1 / ThinClient2 / ThinClient3 (RDP logon) | Active Directory or local SAM | WScript.Network, WTSQuerySessionInformation, registry HKLM\…\Winlogon |
| WinCC user administration | Operator, Maintenance, Administrator | WinCC User Administrator (SIMATIC Logon / WinCC own user DB) | HMIRuntime.User, HMIRuntime.Password |
| Picture / area rights | Authorization levels 0-99 assigned to a WinCC user | Graphics Designer picture properties | Picture-level @UserPermission check |
The Windows user is therefore the key that allows WinCC to select which of the three configured WinCC user profiles to impersonate for picture routing. The script in the WebNavigator picture is the only reliable place to read it, because that script executes in the user's own RDP session.
Prerequisites
- WinCC 7.4 SP1 or later (VBScript 5.6+ is built into the WinCC VBS environment). Earlier 7.0/7.3 versions also work but require a manual install of
scrrun.dllin some terminal server configurations. - WebNavigator client published via RemoteApp, or full Desktop session with IE pinned to the WebNavigator URL.
- The WebNavigator client must run with "Run as current Windows user" enabled so the IE process inherits the RDP user's token (default in WinCC 7 WebNavigator Configuration > Web Client > Process Mode).
- VBS scripting must be enabled in the Internet Explorer Enhanced Security Configuration (ESC). For Terminal Server / published IE, disable ESC for the relevant zone or push the policy through GPO.
- WinCC picture must have an event configured to host a VBS action (e.g. Open picture event) where the VBS can fire.
Method 1: WScript.Network.UserName (Recommended)
The fastest and most portable method. It returns the username of the current Windows logon session, which on a Terminal Server is the RDP user, not the console user. This is the field-proven method that has been deployed in multiple WinCC 7 thin-client production cells.
Read the value into a WinCC internal tag:
' Trigger: OpenPicture event of the start picture
Sub OnOpen()
Dim oNet
Dim sUser
Set oNet = CreateObject("WScript.Network")
sUser = oNet.UserName
' Optional: include domain
' sUser = oNet.UserDomain & "\" & oNet.UserName
HMIRuntime.Tags("LoggedWinUser").Write sUser
HMIRuntime.Tags("LoggedWinUser").Read ' forces server-side update
End Sub
Route the picture by user:
Sub OnOpen()
Dim sUser
Dim sPicture
sUser = HMIRuntime.Tags("LoggedWinUser").Read
Select Case sUser
Case "ThinClient1" : sPicture = "Pagina_Infeed.Pdl"
Case "ThinClient2" : sPicture = "Pagina_Modify.Pdl"
Case "ThinClient3" : sPicture = "Pagina_Outfeed.Pdl"
Case Else : sPicture = "Pagina_Overzicht.Pdl"
End Select
HMIRuntime.Screens("Hoofdscherm").ScreenItems("SchermHoofd").ScreenName = sPicture
End Sub
Why this works on Terminal Server: The WebNavigator client picture script executes inside the IE process that the RDP user launched. The WScript.Network COM object is created in that process, so the security token is the RDP user's token. The returned UserName property is therefore the active thin-client account, not the WinCC service account or console session.
LoggedWinUser as type Text tag 8-bit character set, length 32. Enable the Update attribute in the WinCC Tag Management. On slow terminal servers, read the tag back with .Read immediately after .Write to avoid a one-cycle race condition when subsequent picture code inspects it.Method 2: Registry Read (AltDefaultUserName)
Read the default username cached by the Winlogon subsystem at HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AltDefaultUserName. This key is written by the RDP-Tcp listener when a new session is created and is reliable for the published-WebNavigator scenario, but it returns the last default username, not strictly the current one, so use it as a fallback only.
Sub OnOpen()
Dim oWsh
Dim sUser
Set oWsh = CreateObject("WScript.Shell")
On Error Resume Next
sUser = oWsh.RegRead("HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AltDefaultUserName")
If Err.Number <> 0 Then
sUser = "unknown"
Err.Clear
End If
On Error Goto 0
HMIRuntime.Tags("LoggedWinUser").Write sUser
End Sub
Variants to know about in the same registry path:
| Value | Type | Meaning |
|---|---|---|
AltDefaultUserName |
REG_SZ | Last username typed at the logon screen of the console session. |
AltDefaultDomainName |
REG_SZ | Domain of the same user. |
DefaultUserName |
REG_SZ | Auto-logon target (rarely populated on a TS). |
LastUsedUsername |
REG_SZ | Cache used by the credential provider (Windows 7+). |
This is the registry-hacking method mentioned as a viable alternative in the source thread. Avoid on RDS hosts with multiple concurrent sessions because the value is global, not per-session.
Method 3: Batch File + File Read (Fallback)
Use when WScript.Network is locked down by GPO or when running in a non-interactive session. A scheduled task or a login script writes the username to a file; WinCC reads it back with the fgets ANSI C standard function.
Step 1 — login.cmd (placed in each user's Startup folder or pushed by GPO logon script):
@echo off
echo %USERNAME% > D:\WinCCUser\username.txt
echo %SESSIONNAME% >> D:\WinCCUser\session.txt
Step 2 — WinCC C action reading the file:
#include "apdefap.h"
void OnOpen(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
char szUser[64] = {0};
FILE* fp = fopen("D:\\WinCCUser\\username.txt", "r");
if (fp)
{
fgets(szUser, sizeof(szUser), fp);
fclose(fp);
}
SetTagChar("LoggedWinUser", szUser);
}
Method 4: WTSQuerySessionInformation via WinAPI
For a single-process deployment where the script must enumerate all active sessions (e.g. for an audit overview picture), call WTSQuerySessionInformationW from Wtsapi32.dll. This is the only method that returns the session ID and connection state in addition to the username.
' Requires WTSAPI32 declared in a C action or via a custom COM wrapper.
' Pseudocode only; WinCC VBS does not support Declare natively.
' Use a C action instead (see code below).
#include "apdefap.h"
#include <windows.h>
#include <Wtsapi32.h>
#pragma comment(lib, "Wtsapi32.lib")
void ListActiveSessions()
{
PWTS_SESSION_INFO pInfo = NULL;
DWORD dwCount = 0;
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pInfo, &dwCount))
{
for (DWORD i = 0; i < dwCount; i++)
{
LPTSTR pUser = NULL;
DWORD dwLen = 0;
if (pInfo[i].State == WTSActive &&
WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
pInfo[i].SessionId,
WTSUserName,
&pUser, &dwLen) && pUser)
{
SetTagCharByName("WinCCActiveUsers",
(const char*)pUser);
WTSFreeMemory(pUser);
}
}
WTSFreeMemory(pInfo);
}
}
WTSEnumerateSessions returns all sessions to any process running as a service started by the local system or network service account, which is the default for the WinCC service.Implementing Screen Routing by User
Combine Method 1 (WScript.Network) with a WinCC Picture Window and a small Select Case block. The picture window's ScreenName property is updated dynamically based on the resolved user.
| WinCC User (configured in User Administrator) | Windows RDP user | Authorization (0-99) | Picture loaded | Allowed actions |
|---|---|---|---|---|
| Operator | ThinClient1 / ThinClient3 | 30 | Infeed / Outfeed | Start, Stop, Acknowledge alarms |
| Maintenance | ThinClient2 | 60 | Modify | Operator rights + Setpoint changes, Recipe edits |
| Administrator | (locked to console only) | 99 | All pictures | Full access including WinCC Explorer |
Map the Windows user to the WinCC user programmatically in the VBS using HMIRuntime.Runtime.ProjectName and a private dictionary object that you keep in HMIRuntime global memory if needed. For most projects, hard-coding the Select Case is sufficient and easier to audit.
WinCC User Administration Mapping
Open the WinCC Explorer, expand User Administrator, and create the three WinCC users. For each user, assign the relevant authorization numbers (e.g. User-defined authorization 30 = Operator, 60 = Maintenance, 99 = Administrator). In the picture properties of each subpicture, set the Operator authorization field to the level the user must hold to view it.
When the VBS fires, the user is logged on automatically with the Windows identity if SIMATIC Logon is configured (SIMATIC Logon maps Active Directory users to WinCC users transparently). If SIMATIC Logon is not in use, call:
HMIRuntime.Logon "Operator", "" ' password blank because we are using Windows auth
after writing the tag, so the picture-tree authorization check uses the right WinCC identity immediately.
Security and Permission Considerations
- Credentials are not exposed. Only the username is read. The password of the RDP user is never available to the WinCC runtime by design.
- Auditing. Add the resolved username to the UserLog column of alarm logging so the alarm archive contains a clear attribution per event.
- DCOM. If the WebNavigator client is a separate machine (not a published IE on the same server), the WScript.Network call executes locally on the client, which is what you want. It will return the local Windows user of the client, not the server. This is normally the desired behavior because the thin client has its own logon session.
-
Group Policy. If GPO strips
WScript.Network(rare; usually only done with AppLocker WDAC rules), fall back to Method 3 or Method 4. - IE ESC. Disable Enhanced Security Configuration for the Trusted Sites zone on the TS so the WebNavigator URL runs as expected.
Verification and Testing
- Open the WinCC project, set Computer > Properties > Startup to enable Start Web Navigator Client.
- On the Terminal Server, open an RDP session as
ThinClient1. Launch the published WebNavigator URL. Confirm the start picture shows Infeed. - Open a second RDP session as
ThinClient2. Confirm the start picture shows Modify and that theLoggedWinUsertag in WinCC Tag Simulator showsThinClient2. - Add a temporary diagnostic button to the start picture that writes
HMIRuntime.UserandLoggedWinUserto two additional tags. Both values should match the expected WinCC and Windows identities. - Disable the network connection briefly to verify that the tag write is not lost if the picture is open during a brief RDP glitch. The internal tag should retain the last known value.
- Stop the WinCC Runtime. Verify that the username stored in
D:\WinCCUser\username.txt(if Method 3 is also deployed) matches the last RDP user.
Troubleshooting Matrix
| Symptom | Likely cause | Resolution |
|---|---|---|
Tag always shows the WinCC service account (e.g. SYSTEM or CCUser). |
Script runs in the WinCC server context, not in the RDP IE process. Most often: a server-side C action instead of a picture VBS. | Move the read into the WebNavigator picture's Open picture VBS. Confirm the picture was opened by the WebNavigator client, not a WinCC server-side change picture. |
| WScript.Network returns empty string. | IE ESC is blocking the active-script tag. Or the WScript component is not registered (rare on modern Windows). | Re-register with regsvr32 wshom.ocx. Lower IE security for the WinCC WebNavigator URL zone. Check Application event log for Active Scripting errors. |
| Two RDP sessions both see the same username. | WinCC Server picture was changed via C-Action (server-side) rather than in the WebNavigator client picture. Server-side scripts are shared across sessions. | Place the read code in a picture opened on the WebNavigator client only, never in a server-side scheduled task. |
| Registry read returns ThinClient1 for all sessions. | The AltDefaultUserName value is a single global cache, not per-session. |
Switch to Method 1 or 4. Only use Method 2 on dedicated console-only servers. |
| File-read method shows the previous user's name after re-login. | Stale username.txt from the previous RDP session. |
Add a line del D:\WinCCUser\username.txt at the start of the login script. Or timestamp the file and reject reads older than N seconds. |
| HMIRuntime.Screens() returns "Invalid object" error. | Picture window name is wrong, or the picture is opened on the WinCC server where the named picture window does not exist. | Use HMIRuntime.ActiveScreen instead and reference the picture window by its own Name property in the Graphics Designer. |
| Error 0x80004005 (Unspecified error) on WScript.Network creation. | DCOM is locked down for the user. Or the script is being executed under the WinCC service identity rather than the RDP user. | Enable DCOM for the user in dcomcnfg. Verify the IE process is launched in the RDP session (Task Manager shows the right username in the User Name column). |
Performance and Caching Notes
The username does not change during a single RDP session for any practical purpose, so the VBS only needs to run once at picture open. To avoid hammering the COM subsystem on every picture change, store the resolved user in a project-wide Text variable 8-bit internal tag and re-use it from every picture's Open event. If the user does log out and another logs in to the same RDP session (rare with Thin Clients, common in generic RDS), add a one-second cyclic script that re-reads WScript.Network.UserName and triggers a re-route only on a change.
On a hot runtime with thousands of tags, the COM call adds roughly 5-15 ms of latency on first call, dropping to sub-millisecond on subsequent calls because the COM object is cached. Picture open time will not be visibly affected.
Why does HMIRuntime.User not return the same name as the Windows user?
HMIRuntime.User returns the active WinCC user (Operator / Maintenance / Administrator) configured in the WinCC User Administrator, which is independent of the Windows logon. It is the WinCC-side identity used for picture authorization. To read the Windows logon, you need WScript.Network.UserName or one of the alternative methods above.
Can I get the Windows username in a server-side C action?
No. A C action scheduled on the WinCC server runs under the WinCC service identity, so the username it sees is the service account (often SYSTEM or CCUser). The username of an RDP user is only visible to a process running inside that user's RDP session, which means the VBS must live in the WebNavigator client picture or in a published IE on the terminal server.
Will WScript.Network.UserName work over HTTPS / TLS?
Yes. The username is read from the local Windows logon session, not from the network connection. The WebNavigator transport (HTTP or HTTPS) is irrelevant to this call. The username is also not transmitted to or from the WinCC server; it stays inside the IE process where the script runs.
What if the thin client uses Smart Card or SSO to log on to the TS?
WScript.Network.UserName returns the account name resolved by the logon provider, which is the same string shown in Task Manager for the IE process. For Smart Card logon the UPN is used; for SSO the cached Kerberos identity is used. Either way the value is a usable, consistent username for your Select Case logic.
Is there a way to get the username without any scripting?
Only the file-read method (Method 3) needs VBS or C inside WinCC. The username itself can be captured by a Group Policy logon script, a Scheduled Task triggered by logon, or the RDP-Tcp listener's registry value. The cleanest way to expose it to WinCC is still the WScript.Network WSH call, because it does not depend on any file system or external state.
Does the technique also work for WinCC Professional (TIA Portal)?
Yes, the WScript.Network COM object is available in WinCC Runtime Professional scripts (VB and C) on a terminal server, with the same caveats about server-side vs. client-side execution. For a Unified PC runtime, the equivalent is the Screen.Items system function or the Runtime API's GetCurrentUser method, which already returns the Windows user.