Как получить имя текущего пользователя Windows в C#?
Правильный способ получения имени текущего пользователя в Windows
Вы столкнулись с классической проблемой — разница между пользователем, запустившим процесс, и пользователем, вошедшим в систему. Давайте разберем оба подхода.
1. Environment.UserName — быстрый, но ограниченный
Этот метод возвращает имя пользователя, под которым запущен текущий процесс. Он берется из переменной окружения. Плюсы — скорость, минусы — если приложение запущено от SYSTEM или через runas, вы получите не то, что ожидаете.
// Возвращает: "SYSTEM", "IIS APPPOOL\DefaultAppPool" или "Вася"
string name = Environment.UserName;
2. WindowsIdentity.GetCurrent() — для Windows-аутентификации
Возвращает объект WindowsIdentity, который содержит токен безопасности текущего потока. Работает только на Windows, требует ссылки на System.Security.Principal.
using System.Security.Principal;
WindowsIdentity identity = WindowsIdentity.GetCurrent();
string name = identity.Name; // "DOMAIN\Username" или "MACHINE\Username"
Этот способ тоже ориентирован на контекст выполнения, а не на интерактивного пользователя.
3. Решение: получаем пользователя, который вошел в систему (интерактивная сессия)
Чтобы получить пользователя, который реально сидит за компьютером (например, через RDP или локально), нужно использовать Windows API. Вот проверенный способ для .NET:
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
public class InteractiveUserHelper
{
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern IntPtr WTSOpenServer(string pServerName);
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern void WTSCloseServer(IntPtr hServer);
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern int WTSEnumerateSessions(
IntPtr hServer,
int Reserved,
int Version,
ref IntPtr ppSessionInfo,
ref int pCount);
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern bool WTSQuerySessionInformation(
IntPtr hServer,
int sessionId,
int wtsInfoClass,
out IntPtr ppBuffer,
out int pBytesReturned);
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern void WTSFreeMemory(IntPtr pMemory);
private const int WTS_CURRENT_SERVER_HANDLE = 0;
private const int WTSUserName = 5;
private const int WTSDomainName = 7;
private const int WTSConnectState = 9;
public static string GetInteractiveUserName()
{
IntPtr serverHandle = WTSOpenServer(Environment.MachineName);
try
{
IntPtr sessionInfo = IntPtr.Zero;
int sessionCount = 0;
if (WTSEnumerateSessions(serverHandle, 0, 1, ref sessionInfo, ref sessionCount) == 0)
return null;
try
{
// Размер структуры WTS_SESSION_INFO (4 байта SessionId + 4 байта pWinStationName + 4 байта State)
int structSize = Marshal.SizeOf(typeof(int)) * 3;
IntPtr current = sessionInfo;
for (int i = 0; i < sessionCount; i++)
{
int sessionId = Marshal.ReadInt32(current);
int state = Marshal.ReadInt32(current + 8); // State — третье поле
// Нас интересует активная сессия (WTSActive = 0)
if (state == 0)
{
string userName = QuerySessionInfo(serverHandle, sessionId, WTSUserName);
string domain = QuerySessionInfo(serverHandle, sessionId, WTSDomainName);
if (!string.IsNullOrEmpty(userName))
return $"{domain}\\{userName}";
}
current += structSize;
}
}
finally
{
WTSFreeMemory(sessionInfo);
}
}
finally
{
WTSCloseServer(serverHandle);
}
return Environment.UserName; // fallback
}
private static string QuerySessionInfo(IntPtr serverHandle, int sessionId, int infoClass)
{
IntPtr buffer = IntPtr.Zero;
int bytesReturned = 0;
if (WTSQuerySessionInformation(serverHandle, sessionId, infoClass, out buffer, out bytesReturned))
{
try
{
return Marshal.PtrToStringUni(buffer);
}
finally
{
WTSFreeMemory(buffer);
}
}
return null;
}
}
// Использование:
string realUser = InteractiveUserHelper.GetInteractiveUserName();
Console.WriteLine($"Реальный пользователь: {realUser}");
Когда что использовать?
- Environment.UserName — для простых логов, когда приложение запускается пользователем напрямую.
- WindowsIdentity.GetCurrent() — для проверки прав доступа, работы с Impersonation.
- WTS API — когда нужно узнать, кто сидит за компьютером, независимо от того, как запущено приложение (сервис, планировщик, etc.).
Обратите внимание: WTS API работает только на Windows и требует прав администратора для некоторых вызовов. Для .NET Core/.NET 5+ код будет тем же самым, так как используется P/Invoke.
<<Альтернатива через WMI (проще, но медленнее)
Если вам не хочется возиться с P/Invoke, можно использовать WMI-запросы. Этот подход работает в .NET Framework и .NET Core (с пакетом System.Management).
using System;
using System.Management;
public static string GetCurrentUserViaWmi()
{
string query = "SELECT UserName FROM Win32_ComputerSystem";
using (var searcher = new ManagementObjectSearcher(query))
{
foreach (ManagementObject obj in searcher.Get())
{
string userName = obj["UserName"]?.ToString();
if (!string.IsNullOrEmpty(userName))
return userName;
}
}
return Environment.UserName;
}
// Использование:
string user = GetCurrentUserViaWmi();
Console.WriteLine($"Пользователь (WMI): {user}");
Этот метод возвращает домен\имя пользователя, который вошел в систему. Минусы: требуется ссылка на System.Management.dll, работает медленнее, чем прямой вызов WinAPI, и может быть заблокирован политиками безопасности.
Для большинства случаев я рекомендую первый вариант с WTS API как самый надежный, но WMI-подход — отличная альтернатива для быстрых прототипов.
Ответов пока нет.
Войдите чтобы оставить ответ