Seat Management
SeatUpdater, SAS2, package install, startup, and recovery notes are consolidated here from the 2026-05-19 snapshot.
Deep-only retained findings
gitlab-master.nvidia.com/ngn-gia-storage/gfn/gameseat/seat-admin-service-2.0and package subpaths are embedded in SAS2 symbols.
2026-05-19 application notes
AnalyzeGameStreamMergedLog.exe
What this program actually does
AnalyzeGameStreamMergedLog.exe is a py2exe-frozen Python 2.7 console utility that post-processes the merged GameStream log from GameStreamLogsMerger. It reads GameStreamLogs.log, applies line-level filtering (ignoreLineMatch, properLineMatch, properLogLines), and writes a trimmed output with a before/after line count summary.
Embedded strings confirm output format: Original Line Count: %d Trimmed Count: %d.
Runs as step 2 in post_session_backuplog.bat immediately after the merger step.
Architecture / control flow
post_session_backuplog.bat
└─ python AnalyzeGameStreamMergedLog.py %AG_LOGS%\gslogs\GameStreamLogs.log
├─ open inputLogFilename (CLI arg 1)
├─ readlines / properLogLines loop
├─ ignoreLineMatch → drop noise lines
├─ properLineMatch / formedLine → keep useful lines
└─ write GameStreamLogs_Trimmed.log
└─ aws_log_uploader.py may upload gslogs/*Embedded bytecode also contains GameStream/NSS certificate-validation strings (from bundled library code, not necessarily executed at runtime):
RegistryStorage.+InstallLocation; value: C:\\Program Files\\NVIDIA Corporation\\NvStreamSrvs>Impersonating as NSS to validate SSAS and NSS certificatesSSAS and NSS already have consistent certificates
Windows API surface
| Category | APIs (py2exe bootloader) |
|---|---|
| File I/O | CreateFileA, CreateFileMappingA, GetFileSize, CloseHandle |
| Memory | VirtualAlloc, VirtualProtect, VirtualFree |
| Module load | LoadLibraryA, GetProcAddress, GetModuleHandleA |
| CRT | MSVCR90.dll |
Identical bootloader import surface to GameStreamLogsMerger.exe (shared py2exe stub).
PE metadata (readpe / radare2)
| Field | Value |
|---|---|
| Path | services/SeatUpdater/AnalyzeGameStreamMergedLog/AnalyzeGameStreamMergedLog.exe |
| Format | PE32 CUI; py2exe zip overlay |
| Architecture | x86 (32-bit) |
| Size | 1,645,155 bytes |
| SHA-256 | bbf9e5a2584664e3fb235c76a01f75a8c22dd2fb6c17786055fdc8375079346 |
| Bootloader timestamp | Mon Nov 10 10:40:34 2008 (py2exe stub, not app build date) |
| Entry | 0x00402b28 |
| CLR | None |
Deployment and references
| Item | Evidence |
|---|---|
| Orchestrator | services/SeatUpdater/post_session_backuplog.bat |
| Invocation | c:\python27\python.exe %AG_HOME%\services\SeatUpdater\AnalyzeGameStreamMergedLog.py %AG_LOGS%\gslogs\GameStreamLogs.log > %AG_LOGS%\gslogs\GameStreamLogs_Trimmed.log |
| Input | %AG_LOGS%\gslogs\GameStreamLogs.log |
| Output | %AG_LOGS%\gslogs\GameStreamLogs_Trimmed.log |
| Pipeline order | Merger → Analyzer → exit code file |
| Sysmon allowlist | C:\Asgard\services\SeatUpdater in NGN rules |
Runtime evidence (logs)
No log in this snapshot references AnalyzeGameStreamMergedLog by name. Expected output GameStreamLogs_Trimmed.log is not present in captured %AG_LOGS%\gslogs\.
Not verified
- Exact ignore/proper line regex or prefix lists (source
.pynot in workspace). - Whether trimmed or untrimmed log is uploaded by
aws_log_uploader.py. - Production use of frozen
.exevs.python.exe+.py.
Evidence
readpe,r2_analyze.sh,stringsonAnalyzeGameStreamMergedLog.exeservices/SeatUpdater/post_session_backuplog.bat
GameStreamLogsMerger.exe
What this program actually does
GameStreamLogsMerger.exe is a py2exe-frozen Python 2.7 console utility that collects scattered GameStream session logs from multiple on-seat locations (NvStreamer, NvStreamSvc, NSS, Steam, SSAS, NvBackend, GsUserPlugins) and merges them into a single chronological GameStreamLogs.log. It runs as step 1 of the SeatUpdater post-session log backup pipeline.
Deployment batch files invoke the .py source via c:\python27\python.exe; the frozen .exe is a self-contained alternate entry point with colocated python27.dll.
Architecture / control flow
post_session_backuplog.bat
└─ python GamestreamLogsMerger.py -l 95 -o %AG_LOGS%\gslogs -u C:\users\kiosk
├─ argparse: -l (log level/percent), -o (output dir), -u (user profile)
├─ copyLogs / copylogfiles / appendLogFiles
├─ mergeAndSortLogs (timestamp-ordered merge)
├─ sanitizeBackendLogs (NvBackend-specific cleanup)
└─ write GameStreamLogs.log
└─ AnalyzeGameStreamMergedLog.py (downstream trim)Embedded entry: GamestreamLogsMerger.py (note spelling). Bootloader from Jenkins path C:\Jenkins\snoopy_venv_2715\lib\site-packages\py2exe\boot_common.py.
Log source bitmask (embedded legend):
| Bit | Component |
|---|---|
| 1 | NvStreamer |
| 2 | NvStreamSvc |
| 4 | NSS |
| 8 | Steam |
| 16 | SSAS |
| 32 | NvBackend |
| 64 | GsUserPlugins |
Combinations like NvStreamer+NvStreamSvc(3) are supported.
Windows API surface
| Category | APIs (py2exe bootloader) |
|---|---|
| File I/O | CreateFileA, CreateFileMappingA, GetFileSize, CloseHandle, GetFullPathNameA |
| Memory | VirtualAlloc, VirtualProtect, VirtualFree, HeapAlloc, HeapFree |
| Module load | LoadLibraryA, GetProcAddress, GetModuleHandleA |
| Process | CreateProcess, GetExitCodeProcess (embedded Python subprocess path) |
| CRT | MSVCR90.dll (fprintf, malloc, getenv, atoi) |
No direct network or WMI imports — pure filesystem log aggregation.
PE metadata (readpe / radare2)
| Field | Value |
|---|---|
| Path | services/SeatUpdater/GameStreamLogsMerger/GameStreamLogsMerger.exe |
| Format | PE32 CUI; file also reports Zip archive, with extra data prepended (py2exe overlay) |
| Architecture | x86 (32-bit) |
| Size | 1,865,172 bytes |
| SHA-256 | 187fd156d3de8d9c3bd1294e021ca6a1486394c7a3ee41422f2b9806a56d8f5e |
| Bootloader timestamp | Thu Jun 18 10:45:59 2015 |
| Linker | MSVC 9.0 |
| Entry | 0x00402b28 |
| CLR | None |
Deployment and references
| Item | Evidence |
|---|---|
| Orchestrator | services/SeatUpdater/post_session_backuplog.bat |
| Invocation | c:\python27\python.exe %AG_HOME%\services\SeatUpdater\GamestreamLogsMerger.py -l 95 -o %AG_LOGS%\gslogs -u C:\users\kiosk |
| Merger log | %AG_LOGS%\gslogs\gslogmerger.log |
| Output | %AG_LOGS%\gslogs\GameStreamLogs.log |
| Exit code file | %AG_HOME%\services\SeatUpdater\post_session_backuplog.ExitCode |
| Upload | aws_log_uploader.py glob includes %AG_LOGS%\gslogs\*.* |
| Sysmon allowlist | tools/Sysmon/sysmon-ngn.xml — CommandLine contains C:\Asgard\services\SeatUpdater |
Runtime evidence (logs)
No gslogmerger.log or GameStreamLogs.log captured in this workspace snapshot. No runtime log references the .exe by name — batch always invokes .py.
aws_log_uploader.py stops GridPerf before log upload (logman stop GridPerf) but does not reference the merger directly.
Not verified
- Exact semantics of
-l 95(string(percent).appears near merger logic; likely log-level filter at 95%). - Full filesystem scan paths beyond
-u C:\users\kiosk. - Whether production seats ever invoke the frozen
.exevs. alwayspython.exe+.py.
Evidence
readpe,r2_analyze.sh,stringsonGameStreamLogsMerger.exeservices/SeatUpdater/post_session_backuplog.bat,aws_log_uploader.py
SAS-2.0-windows-amd64.exe
What this program actually does
SAS-2.0-windows-amd64.exe is Seat Admin Service 2.0 — the first-boot orchestrator for a GeForce NOW gameseat. It mounts cloud-init metadata, parses seat identity and network userdata, configures multi-NIC Windows networking (APP / STREAM / STORAGE), syncs time, starts log shipping, validates Windows licensing, then pulls and installs the Pandora tenant stack from SMB storage servers.
It is invoked from sas2/start/startupchild.bat and reads sas2/config/sas2_config.json.
Source tree (strings): gitlab-master.nvidia.com/ngn-gia-storage/gfn/gameseat/seat-admin-service-2.0/
Build workspace path (strings): /home/jenkins/jenkins/workspace/SAS-2.0-Promotion/pkg/stages/
Architecture (from Go symbol strings)
SAS/main.go
└─ stages/registry.go — ordered stage runner
├─ stage_mount.go — metadata CD / C:\Asgard\conf
├─ stage_metadata.go — metadata.txt, networkdata, userdata
├─ stage_network.go — GN2 adapter groups
├─ stage_timesync.go — w32time
├─ stage_fluentbit.go — remote log forwarding
├─ stage_license.go — Windows activation check
└─ stage_run.go — Pandora install via SASSoftwareInstallerEXE
└─ lib_metadata/, lib_network/, lib_license/, lib_run/
└─ telemetry/ — Kratos CloudEvents
└─ sas_logger/ — success/failure markersPipeline stages (from logs/sas2/sas2.log)
Stages appear as JSON "stage" fields. On success (2026-05-19 boot) they run in this order:
| Order | Stage | Source file | Behavior (log evidence) |
|---|---|---|---|
| 1 | mount | stages/stage_mount.go, lib_mount/mount_windows.go | Scan drives for CDFS metadata CD; copy metadata, networkdata, userdata to C:\Asgard\conf; symlink userdata from ISO |
| 2 | metadata | stages/stage_metadata.go, lib_metadata/metadata.go | Read metadata.txt, GN2 networkdata, userdata; emit Instance-ID / Zone / Pool to telemetry |
| 3 | network | lib_network/gn2_adapter_group_windows.go | Match NICs by MAC; rename to APP, STREAM, STORAGE; static IPs, routes, DNS, SMB Direct/multichannel, DSCP on STORAGE |
| 4 | timesync | stages/stage_timesync.go | Start/sync w32time |
| 5 | fluentbit | stages/stage_fluentbit.go | Write fluent-bit config; forward logs to logging server over TCP |
| 6 | license | lib_license/license_windows.go | Check Windows Professional Workstation activation; skip if already activated |
| 7 | run | stages/stage_run.go, lib_run/run_windows.go | Probe storage servers on TCP 445; invoke SASSoftwareInstallerEXE.exe for Pandora |
Failure before metadata (May 8 boots): repeated SAS_MetadataParseFailed — metadata.txt missing when no CDFS drive present and C:\Asgard\conf empty.
Success marker: SAS 2.0 has successfully completed + Recorded SAS success (sas_logger/success_logger.go).
Stage details — successful boot timeline (2026-05-19)
| Time (UTC) | Stage | Event |
|---|---|---|
| 18:41:58 | mount | Found CD D: CDFS; copied metadata to C:\Asgard\conf |
| 18:41:58 | metadata | Instance [REDACTED_INSTANCE_ID], pool [REDACTED_POOL], zone [REDACTED_ZONE] |
| 18:41:58 | metadata | SAS config flags: DisableVNC:true, SMBDirectStorage:true, LoggingOverTcp:true, EnableRsyslog:true, … |
| 18:41:58–18:42:37 | network | APP [REDACTED_IP], STREAM [REDACTED_IP], STORAGE [REDACTED_IP]; RoCE → SMB multichannel + SMB direct |
| 18:42:37 | network | Seat successfully connected to the internet |
| 18:42:40 | fluentbit | Logging server [REDACTED_IP]; fluent-bit service started |
| 18:42:43 | license | Windows already activated (status 1) — skipped |
| 18:42:43 | run | Storage servers [REDACTED_IP],[REDACTED_IP],[REDACTED_IP] reachable |
| 18:42:43 | run | SASSoftwareInstallerEXE.exe C:\Asgard\sas2\bin\pandora_install_times.json sas2 |
| 18:43:25 | run | Stage complete; Kratos telemetry sent; SAS 2.0 has successfully completed |
SAS error codes (strings)
| Code | Context |
|---|---|
SAS_MetadataParseFailed | Cannot read/parse seat metadata |
SAS_ConfigurationFileNotFound / SAS_ConfigurationParseFailed | Config load failures |
SAS_OSLicenseActivationFailed | Windows activation |
SAS_GPULicenseInitFailed / SAS_GPULicenseValidationFailed | GPU licensing (not hit in sampled log) |
SAS_RunLocalExecutableFailed / SAS_RunStorageServerExecutableFailed | Run stage subprocess failures |
SAS_GenericError | Catch-all |
Configuration
| File | Keys (evidence) |
|---|---|
sas2/config/sas2_config.json | sas2_githash: 0d77c84, seat_type: gameseat, tenant_installer_source: storage-server, tenant_binary_path: C:\Asgard\pandora\dist\startup\startup.exe |
| Seat userdata (log) | Storage server list, DNS servers, logging server IP, SAS feature flags |
C:\Asgard\conf\metadata.txt | Instance-ID, zone, pool |
C:\Asgard\conf\networkdata | GN2 link definitions (net1, net2, eth0) |
C:\Asgard\conf\userdata | Seat-level SAS toggles |
Telemetry
Each failed or completed stage sends Kratos CloudEvents (telemetry/telemetry.go, telemetry/event_data.go). Boot time captured via telemetry/telemetry_windows.go.
Relationships
| Component | Role |
|---|---|
SASSoftwareInstallerEXE.exe | Clones/mounts Pandora VHDX from SMB; runs B:\deploy\run.bat |
LaunchProcessAsUser.exe | Referenced in sas2 tree for user-context launches (not in successful run log) |
gs2-agent, mb-repeater | Start later via Pandora/startup chain (~18:42:49+) |
GSConfigurator (GSP) | Not called by SAS directly; downstream services consume CSR configs |
Not verified
- Full ordered stage list in binary if config disables stages (only 7 stages seen in log).
- GPU license stage — symbols exist; not executed in sampled successful run.
stage_example.goexists in build tree; not observed at runtime.
Evidence
stringsonsas2/bin/SAS-2.0-windows-amd64.exe(docs/reverse-engineering/_analysis/SAS-2.0-windows-amd64.strings.txt)logs/sas2/sas2.logsas2/config/sas2_config.jsonlogs/sas2/SASSoftwareInstallerEXE.log
SASSoftwareInstallerEXE.exe
What this program actually does
SASSoftwareInstallerEXE.exe clones tenant software VHDX images from SMB storage servers, attaches them locally, runs each app's deploy\run.bat, records timing metrics, and cleans up VHDX files. Invoked by SAS 2.0 run stage:
SASSoftwareInstallerEXE.exe C:\Asgard\sas2\bin\pandora_install_times.json sas2Pandora install timeline (from logs/sas2/SASSoftwareInstallerEXE.log)
| Time | Event |
|---|---|
| 18:42:43 | Storage servers: [REDACTED_IP], [REDACTED_IP], [REDACTED_IP] |
| 18:42:43 | Mount SMB \\[REDACTED_IP]\software → A:\ |
| 18:42:43 | Clone VHDX pandora-main-dae006e-202655141656.vhdx to c:\asgard\vhdx\PANDORA\ |
| 18:42:43 | Attach → mount point B:\ |
| 18:42:43 | Run B:\deploy\run.bat → log pandoraSoftwareInstall.log (pid 4084) |
| 18:43:24 | Success; detach/delete VHDX; write metrics JSON |
| 18:43:25 | Metrics: clone 76 ms, mount 38 ms, install 41.3 s |
Flags logged: directIOflag: 0, is_debug_seat: 0, skipping VDK App install (SAS 2.0 path).
Internal modules (log tags)
network_share— SMB share create/mountdisk_helper/disk_connector— VHDX open/attach/detachProcUtilWin32— subprocess run/waitwin_helper— CIFS verify
Output artifacts
| File | Purpose |
|---|---|
C:\Asgard\sas2\bin\pandora_install_times.json | Install timing metrics |
C:\Asgard\logs\sas2\pandoraSoftwareInstall.log | Pandora deploy stdout |
Relationships
| Component | Role |
|---|---|
SAS-2.0-windows-amd64.exe | Invokes this during run stage |
Pandora startup.exe | Downstream tenant entry (per sas2_config.json) |
gs2-agent, mb-repeater | Installed as part of Pandora deploy chain |
Evidence
logs/sas2/SASSoftwareInstallerEXE.loglogs/sas2/sas2.log(run stage invocation)docs/reverse-engineering/_analysis/SASSoftwareInstallerEXE.strings.txt
LaunchProcessAsUser.exe
What this program actually does
LaunchProcessAsUser.exe is a small .NET Framework 4.8 console helper (OSL/Microsoft) that launches a child process under a specified Windows user account using supplied credentials. On Asgard seats, the sas2/bin copy is invoked by sas2/start/startup.bat to run startupchild.bat as the xen kiosk user from a scheduled-task context, bootstrapping SAS-2.0 without requiring an interactive login.
Perforce source: //sw/gcomp/dev/src/OSL/LaunchProcessAsUser/LaunchProcessAsUser/LaunchProcessAsUser/Program.cs (noted in startup.bat).
Architecture / control flow
startup.bat (kiosk scheduled task)
└─ start /wait /b sas2\bin\launchprocessasuser "sas2\start\startupchild.bat"
└─ _CorExeMain (mscoree.dll)
└─ LaunchProcessAsUser.Main
├─ RunAs(path, username, password, args, WorkingDirectory)
├─ ExecuteCommandSync (stdout redirect variant)
├─ ChangeUserPassword
└─ MakeSecureString → ProcessStartInfo → Process.Start → WaitForExitNative PE is a thin CLR host stub; all logic is IL in the embedded assembly.
Windows API surface
| Layer | APIs |
|---|---|
| Native stub | _CorExeMain via mscoree.dll only |
| .NET (inferred) | ProcessStartInfo, Process.Start, WaitForExit, RedirectStandardOutput, SecureString |
| Effective OS | CreateProcessWithLogonW / CreateProcessAsUser (via CLR, not directly imported) |
Credential parameter names in metadata: k_username/x_username, k_password/x_password (obfuscated CLI arg variants).
| r2 confirmed | _CorExeMain (mscoree.dll) |
PE metadata (readpe / radare2)
| Field | Value |
|---|---|
| Path | sas2/bin/LaunchProcessAsUser.exe |
| Format | PE32 CUI, Mono/.NET assembly |
| Architecture | x86 (32-bit) |
| Size | 8,704 bytes |
| SHA-256 | fd73ee2585570c2c34a80724ab04a9bb7fae83e8336dc3eb118335e91ccf31bb |
| Compiled | Wed Nov 22 00:03:24 2023 |
| .NET target | v4.0.30319 / .NET Framework 4.8 |
| Entry | 0x0040355e → jmp _CorExeMain |
| Manifest | requestedExecutionLevel level="asInvoker" |
| PDB | ...\nmela\...\obj\x86\Debug\LaunchProcessAsUser.pdb |
Deployment and references
| Item | Evidence |
|---|---|
| Caller | sas2/start/startup.bat |
| Command | start /wait /b %AG_HOME%\sas2\bin\launchprocessasuser "%AG_HOME%\sas2\start\startupchild.bat" |
| Purpose | Start SAS 2.0 as xen user from kiosk scheduled task |
| Child | startupchild.bat masks log output for SAS bootstrap |
No other config/script in this workspace references sas2/bin/LaunchProcessAsUser.exe by path.
Runtime evidence (logs)
No log file references LaunchProcessAsUser by name. SAS-2 activity appears in logs/sas2/ and logs/startup/startup.log without explicit attribution to this binary.
Comparison: sas2 vs tools copy
| Property | sas2/bin (this file) | tools/ |
|---|---|---|
| Size | 8,704 B | 6,144 B |
| Build | Debug Nov 2023 | Release Mar 2015 |
| .NET | 4.8 | 4 Client Profile |
| Extra methods | ExecuteCommandSync, ChangeUserPassword | Not present |
| Deployed | Yes | No direct reference |
Not verified
- Exact CLI argument order (username, password, domain, executable, args) without decompiling
Program.cs. - Whether
ExecuteCommandSynccaptures stdout synchronously vs. fire-and-forgetRunAs.
Evidence
readpe,r2_analyze.sh,stringsonsas2/bin/LaunchProcessAsUser.execmp/sha256sumvs.tools/LaunchProcessAsUser.exesas2/start/startup.bat