簡體   English   中英

如何使用.NET從多用戶環境中的Windows Service獲取當前Windows用戶名

[英]How to get current windows username from windows service in multiuser environment using .NET

我有一個Windows服務,該服務始終為所有登錄的用戶運行WPF應用程序,並且運行良好,現在在WPF應用程序中,我無法獲得當前的用戶名Environment.UserName; 返回“ SYSTEM”,這是可以理解的。 所以我想是找到可以由Process.GetCurrentProcess()。SessionId檢索的當前進程的會話ID,然后獲取所有登錄到計算機並循環遍歷的用戶的列表,以查找與進程會話匹配的會話ID id和后來的用戶名。

但是我不知道如何獲取所有已登錄用戶的列表,或者如果有人可以幫助我,我將不勝感激。

在MSDN論壇上找到了此解決方案:

using System.Security.Principal;
.
.
.
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
String username = wp.Identity.Name;

現在,可以通過創建新的控制台應用程序,粘貼上面的代碼並將用戶名字符串寫入控制台來輕松測試。 似乎工作正常,但對於服務而言,情況顯然更復雜。 由於所有服務都在SYSTEM用戶下運行的容器中運行,因此它們就是返回的內容。 有關更多信息,請參見下面的鏈接,特別是。 所有朱駿的答案。

http://social.msdn.microsoft.com/Forums/vstudio/en-US/3be119b0-88b4-442e-9613-6856cbb27adb/how-can-i-get-current-username-in-windows-service?forum= csharpgeneral

由於服務與用戶會話完全分開,因此似乎無法實現您想要的目標。

我通過在WPF應用程序中執行powershell命令“ quser”來解決該問題,該命令返回所有已登錄的用戶,然后迭代查找其中應用程序正在使用用戶會話ID運行的會話ID,然后檢索其名稱。 以下是通過傳遞用戶名的會話ID來獲取用戶名的函數

 private string GetUserName(int SessionId)
        {
            try
            {
                Runspace runspace = RunspaceFactory.CreateRunspace();
                runspace.Open();

                Pipeline pipeline = runspace.CreatePipeline();
                pipeline.Commands.AddScript("Quser");
                pipeline.Commands.Add("Out-String");

                Collection<PSObject> results = pipeline.Invoke();

                runspace.Close();

                StringBuilder stringBuilder = new StringBuilder();
                foreach (PSObject obj in results)
                {
                    stringBuilder.AppendLine(obj.ToString());
                }

                foreach (string User in stringBuilder.ToString().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Skip(1))
                {
                    string[] UserAttributes = User.Split(new string[]{" "},StringSplitOptions.RemoveEmptyEntries);
                    if (int.Parse(UserAttributes[2].Trim()) == SessionId)
                    {
                        return UserAttributes[0].Replace(">", string.Empty).Trim();
                    }
                }

                return stringBuilder.ToString();
            }
            catch (Exception ex)
            {
            }

            return string.Empty;
        }

該函數可以通過

string CurrentUser = GetUserName(Process.GetCurrentProcess().SessionId);

在構建Windows服務時遇到了類似的問題。 就像您一樣,我具有會話ID,並且需要獲取相應的用戶名。 Syed的上述回答在我的計算機(Windows 10)上不起作用,因為Microsoft似乎已刪除了quser可執行文件。 經過幾次失敗的解決方案之后,我遇到了這個特殊的答案 ,這啟發了我的解決方案:

這是我的代碼(所有代碼都駐留在一個類中;對於我而言,該類是繼承ServiceBase的類)

    [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,
    }

    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;
    }

您可以嘗試使用此Code Spinet。 每當用戶登錄Windows時,“用戶名”屬性將包含該用戶的用戶名。 如果Windows系統中沒有用戶,則不會有Win32_ComputerSystem類的實例。

ManagementScope ms = new ManagementScope("\\\\.\\root\\cimv2");
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_ComputerSystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ms, query);
foreach(ManagementObject mo in searcher.Get())
{
    Console.WriteLine(mo["UserName"].ToString());
}

我進行了一些搜索,找到了適合您的代碼:
它將獲取正在運行該進程的用戶名...
參考: 如何確定C#中進程的所有者?

public string GetProcessOwner(string processName)
{
string query = "Select * from Win32_Process Where Name = \"" + processName + "\"";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();

foreach (ManagementObject obj in processList)
{
    string[] argList = new string[] { string.Empty, string.Empty };
    int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
    if (returnVal == 0)
    {
        // return DOMAIN\user
        string owner = argList[1] + "\\" + argList[0];
        return owner;       
    }
}

return "NO OWNER";
}

您可以嘗試以下代碼:

string username = "SYSTEM";
var explorer = Process.GetProcessesByName("explorer").FirstOrDefault();
if (explorer != null)
{
    username = GetUsername(explorer.SessionId);
}

此處的GetUsername方法的實現: https ://stackoverflow.com/a/35810391/10412686

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM