如何检索运行Windows服务的用户名?

19

给定服务名称,我想要获取运行该服务的用户名(即服务属性窗口的“登录”选项卡中显示的用户名)。

ServiceController类似乎没有检索此基本信息的任何内容。在System.ServiceProcess中也没有其他看起来公开此信息的东西。

是否有托管解决方案可用,或者我需要降至更低级别的东西?

6个回答

24
使用WMI,通过System.Management模块,您可以尝试以下代码:

使用WMI和System.Management模块,您可以尝试下面的代码:

using System;
namespace WindowsServiceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Management.SelectQuery sQuery = new System.Management.SelectQuery(string.Format("select name, startname from Win32_Service")); // where name = '{0}'", "MCShield.exe"));
            using (System.Management.ManagementObjectSearcher mgmtSearcher  = new System.Management.ManagementObjectSearcher(sQuery))
            {
                foreach (System.Management.ManagementObject service in mgmtSearcher.Get())
                {
                    string servicelogondetails =
                        string.Format("Name: {0} ,  Logon : {1} ", service["Name"].ToString(), service["startname"]).ToString();
                    Console.WriteLine(servicelogondetails);
                }
            }
            Console.ReadLine();
        }
    }
}
你随后可以用你的服务名称替换掉注释代码,这样它只会返回正在运行的你的服务进程实例。

6

3

您可以通过查找Windows注册表并读取以下字符串值来找到这个,将[SERVICE_NAME]替换为Windows服务的名称:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\[SERVICE_NAME]\ObjectName

1
这个解决方案对我来说很好用:

    ManagementObject wmiService = new ManagementObject("Win32_Service.Name='" + this.ServiceName + "'");
    wmiService.Get();
    string user = wmiService["startname"].ToString();

为了帮助 OP 解决当前的问题,可以在回答中添加一些解释说明。 - ρяσѕρєя K

1

试试这个:

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

但最明显的是你会得到LOCAL SYSTEM或NETWORK。之所以不能显示此用户 - 是因为服务可以管理多个用户(共享桌面,附加到当前Windows会话,使用共享资源…)系统启动服务,但任何用户都可以使用它。


然后,您可以从上述命令返回的WindowsIdentity对象中获取Name属性。 - ewall
7
这将返回当前用户的 WindowsIdentity,而不是指定服务的身份。 - Mark Carpenter
@Pwninstein,通常服务是从SYSTEM或NETWORK凭据启动的,而不是从“已登录”的用户启动。请参见我的编辑内容。那么,请澄清您想要获取启动服务的系统帐户(我的答案在这方面是正确的),还是当前已登录用户列表,可以使用此服务? - Dewfy
通常服务以本地系统或网络服务运行,但您可以安装一个服务以标准用户帐户运行(这是我们正在处理的项目中所做的)。 - Mark Carpenter
@Pwninstein - 在这种情况下,您将从GetCurrent()获得正确的结果。 - Dewfy
1
我不确定你是否理解我的意图:我想获取特定服务正在运行的用户名。我希望从完全独立的客户端应用程序中执行此操作(即检索用户名的所有代码都在客户端中)。您建议使用GetCurrent()将无法工作,因为根据MSDN,它“返回表示当前Windows用户的WindowsIdentity对象。”在这种情况下,它将是运行CLIENT应用程序的当前Windows用户的WindowsIdentity,而不是SERVICE的WindowsIdentity。 - Mark Carpenter

0
    public String getUsername() {
    string username = null;
    try {
      ManagementScope ms = new ManagementScope("\\\\.\\root\\cimv2");
      ms.Connect();
      ObjectQuery query = new ObjectQuery
              ("SELECT * FROM Win32_ComputerSystem");
      ManagementObjectSearcher searcher =
              new ManagementObjectSearcher(ms, query);
      foreach (ManagementObject mo in searcher.Get()) {
        username = mo["UserName"].ToString();
      }
      string[] usernameParts = username.Split('\\');
      username = usernameParts[usernameParts.Length - 1];
    } catch (Exception) {
      username = "SYSTEM";
    }
    return username;
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接