从服务获取登录的用户名

我有一项服务,我必须登录到本地管理员进行安装。 当用户登录或注销以记录其用户名时,此服务的目的是记录。 我终于找到了一些我认为可以工作的WMI代码,但它仍然是返回管理员。 为什么这不起作用?

var query = new ObjectQuery("SELECT * FROM Win32_Process WHERE Name = 'explorer.exe'"); var explorerProcesses = new ManagementObjectSearcher(query).Get(); foreach (ManagementObject mo in explorerProcesses) { string[] ownerInfo = new string[2]; mo.InvokeMethod("GetOwner", (object[])ownerInfo); userName = String.Concat(ownerInfo[1], @"\", ownerInfo[0]); } Console.WriteLine(userName); Console.ReadLine(); 

为了澄清我的问题,我想要获得当前登录的用户,但它给了我Adminstrator我用来安装服务的帐户。

您应该使用服务控制管理器通知。 您可以将服务配置为在用户登录和/或注销时接收通知事件。 这允许服务在服务需要时进行交互式用户模拟,但它应该为您提供日志记录所需的信息。

请查看“使用服务控制管理器(SCM)通知”部分, url为http://technet.microsoft.com/en-us/library/cc721961(WS.10).aspx

编辑

在Service类中,重写OnSessionChange事件处理程序以检查登录和注销事件。

 protected override void OnSessionChange(SessionChangeDescription changeDescription) { base.OnSessionChange(changeDescription); switch (changeDescription.Reason) { case SessionChangeReason.SessionLogon: // do your logging here break; case SessionChangeReason.SessionLogoff: // do your logging here break; } } 

EDIT2:

 class Class1 { [DllImport("Advapi32.dll")] static extern bool GetUserName(StringBuilder lpBuffer, ref int nSize); [STAThread] static void Main(string[] args) { StringBuilder Buffer = new StringBuilder(64); int nSize=64; GetUserName(Buffer, ref nSize); Console.WriteLine(Buffer.ToString()); } } 

EDIT3:

 public class InteractiveUser { [DllImport("wtsapi32.dll", SetLastError = true)] static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token); [DllImport("kernel32.dll")] private static extern UInt32 WTSGetActiveConsoleSessionId(); enum TOKEN_INFORMATION_CLASS { TokenUser = 1, TokenGroups, TokenPrivileges, TokenOwner, TokenPrimaryGroup, TokenDefaultDacl, TokenSource, TokenType, TokenImpersonationLevel, TokenStatistics, TokenRestrictedSids, TokenSessionId, TokenGroupsAndPrivileges, TokenSessionReference, TokenSandBoxInert, TokenAuditPolicy, TokenOrigin } public struct TOKEN_USER { public SID_AND_ATTRIBUTES User; } [StructLayout(LayoutKind.Sequential)] public struct SID_AND_ATTRIBUTES { public IntPtr Sid; public int Attributes; } // Using IntPtr for pSID insted of Byte[] [DllImport("advapi32", CharSet=CharSet.Auto, SetLastError=true)] static extern bool ConvertSidToStringSid( IntPtr pSID, out IntPtr ptrSid); [DllImport("kernel32.dll")] static extern IntPtr LocalFree(IntPtr hMem); [DllImport("advapi32.dll", SetLastError=true)] static extern bool GetTokenInformation( IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, out int ReturnLength); private static string GetSID(IntPtr token) { bool Result; int TokenInfLength = 0; string sidAsString = String.Empty; // first call gets lenght of TokenInformation Result = GetTokenInformation( token , TOKEN_INFORMATION_CLASS.TokenUser , IntPtr.Zero , TokenInfLength , out TokenInfLength ); IntPtr TokenInformation = Marshal.AllocHGlobal( TokenInfLength ) ; Result = GetTokenInformation( token , TOKEN_INFORMATION_CLASS.TokenUser , TokenInformation , TokenInfLength , out TokenInfLength ) ; if ( Result ) { TOKEN_USER TokenUser = ( TOKEN_USER )Marshal.PtrToStructure( TokenInformation , typeof( TOKEN_USER ) ) ; IntPtr pstr = IntPtr.Zero; Boolean ok = ConvertSidToStringSid( TokenUser.User.Sid , out pstr ); sidAsString = Marshal.PtrToStringAuto( pstr ); LocalFree(pstr); } Marshal.FreeHGlobal( TokenInformation ); return sidAsString; } public static string Account() { IntPtr token = IntPtr.Zero; String account = String.Empty; if (WTSQueryUserToken(WTSGetActiveConsoleSessionId(), out token)) { String sid = GetSID(token); account = new SecurityIdentifier(sid).Translate(typeof(NTAccount)).ToString(); } else { int err = Marshal.GetLastWin32Error(); switch (err) { case 5: account = "ERROR_ACCESS_DENIED"; break; case 87: account = "ERROR_INVALID_PARAMETER"; break; case 1008: account = "ERROR_NO_TOKEN"; break; case 1314: account = "ERROR_PRIVILEGE_NOT_HELD"; break; case 7022: account = "ERROR_CTX_WINSTATION_NOT_FOUND"; break; default: account = String.Format("ERROR_{0}", err.ToString()); break; } } return account; } } 

这是我的代码(所有代码都驻留在类中;在我的例子中,是inheritanceServiceBase的类)。

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

使用上面的代码,你可以简单地获取你所覆盖的方法中的用户名:

 protected override void OnSessionChange(SessionChangeDescription changeDescription) { string username = GetUsername(changeDescription.SessionId); //continue with any other thing you wish to do } 

尝试更改插入sessionId参数的Account()方法并将changeDescription.SessionId传递给方法WTSQueryUserToken

 public static string Account(uint sessionId) { IntPtr token = IntPtr.Zero; String account = String.Empty; if (WTSQueryUserToken(sessionId, out token)) { ... ... 

ps:使用LocalSystem帐户运行您的服务

我知道这个post很旧,但是如果有人需要知道它是如何工作的:

添加对System.Management的引用

using System.Management; 在文件的顶部

在您的类中创建此私有变量:

 private readonly ManagementClass _wmiComputerSystem = new ManagementClass("Win32_ComputerSystem"); 

在您的服务中创建此方法:

 protected override void OnSessionChange(SessionChangeDescription changeDescription) { base.OnSessionChange(changeDescription); switch (changeDescription.Reason) { case SessionChangeReason.SessionLogon: { string user = ""; foreach (ManagementObject currentObject in _wmiComputerSystem.GetInstances()) { user = currentObject.Properties["UserName"].Value.ToString().Trim(); } } break; } } 

现在您在用户中获得了用户名。 如果计算机位于域中,则它看起来像此domain\username