Как я могу получить текущее имя пользователя из службы Windows в.NET?

У меня есть служба Windows, которая требует текущего имени пользователя. Я старался System.Environment.UserName, Удостоверение Windows и проверка подлинности Windows Form, но все возвращают "System" как пользователь, поскольку моя служба работает в привилегированном режиме. Есть ли способ получить имя пользователя, вошедшего в систему, без изменения типа учетной записи моей службы?

9 ответов

Это запрос WMI для получения имени пользователя:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
ManagementObjectCollection collection = searcher.Get();
string username = (string)collection.Cast<ManagementBaseObject>().First()["UserName"];

Вам нужно будет добавить System.Management под ссылками вручную.

Если вы находитесь в сети пользователей, то имя пользователя будет другим:

Environment.UserName

Будет отображать формат: "Имя пользователя", а не

System.Security.Principal.WindowsIdentity.GetCurrent().Name

Будет отображаться формат: "Имя сети \ Имя пользователя"

Выберите нужный формат.

Решение ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem") работало нормально для меня. НО это не работает, если служба запущена через подключение к удаленному рабочему столу. Чтобы обойти это, мы можем запросить имя пользователя владельца интерактивного процесса, который всегда выполняется на ПК: explorer.exe. Таким образом, мы всегда получаем имя пользователя, выполнившего вход в Windows, из нашей службы Windows:

foreach (System.Management.ManagementObject Process in Processes.Get())
{
    if (Process["ExecutablePath"] != null && 
        System.IO.Path.GetFileName(Process["ExecutablePath"].ToString()).ToLower() == "explorer.exe" )
    {
        string[] OwnerInfo = new string[2];
        Process.InvokeMethod("GetOwner", (object[])OwnerInfo);

        Console.WriteLine(string.Format("Windows Logged-in Interactive UserName={0}", OwnerInfo[0]));

        break;
    }
}

Модифицированный код ответа Тапаса:

Dim searcher As New ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem")
Dim collection As ManagementObjectCollection = searcher.[Get]()
Dim username As String
For Each oReturn As ManagementObject In collection
    username = oReturn("UserName")
Next

Пытаться WindowsIdentity.GetCurrent(), Вам нужно добавить ссылку на System.Security.Principal

Вы также можете попробовать

System.Environment.GetEnvironmentVariable("UserName");

На всякий случай, если кто-то ищет отображаемое имя пользователя, а не имя пользователя, как я.

Вот угощение:

System.DirectoryServices.AccountManagement.UserPrincipal.Current.DisplayName.

Добавить ссылку на System.DirectoryServices.AccountManagement в вашем проекте.

Завершение ответа от @xanblax

private static string getUserName()
    {
        SelectQuery query = new SelectQuery(@"Select * from Win32_Process");
        using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
        {
            foreach (System.Management.ManagementObject Process in searcher.Get())
            {
                if (Process["ExecutablePath"] != null &&
                    string.Equals(Path.GetFileName(Process["ExecutablePath"].ToString()), "explorer.exe", StringComparison.OrdinalIgnoreCase))
                {
                    string[] OwnerInfo = new string[2];
                    Process.InvokeMethod("GetOwner", (object[])OwnerInfo);

                    return OwnerInfo[0];
                }
            }
        }
        return "";
    }

Ответ для службы Windows:

Вы можете получить его изsessionIdпользователя, вошедшего в систему. Сначала вам нужно добавить следующееP/INVOKEскрипт в вашем классе кода:

      [DllImport("Wtsapi32.dll")]
private static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WtsInfoClass wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
[DllImport("Wtsapi32.dll")]
private static extern void WTSFreeMemory(IntPtr pointer);
 
private enum WtsInfoClass
{
    WTSUserName = 5, 
    WTSDomainName = 7,
}

[DllImport("Kernel32.dll", SetLastError = true)]
static extern int WTSGetActiveConsoleSessionId();

Затем добавьте этот метод:

      private static string GetUsername(int sessionId, bool prependDomain = true)
{
    IntPtr buffer;
    int strLen;
    string username = "SYSTEM";
    if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WtsInfoClass.WTSUserName, out buffer, out strLen) && strLen > 1)
    {
        username = Marshal.PtrToStringAnsi(buffer);
        WTSFreeMemory(buffer);
        if (prependDomain)
        {
            if (WTSQuerySessionInformation(IntPtr.Zero, sessionId, WtsInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1)
            {
                username = Marshal.PtrToStringAnsi(buffer) + "\\" + username;
                WTSFreeMemory(buffer);
            }
        }
    }
    return username;
}

Наконец, вызовите метод следующим образом:

      int sessionId = WTSGetActiveConsoleSessionId();
string username = GetUsername(sessionId); // Gives 'Domain\Username'

Ссылки на источники:

Другие вопросы по тегам