我有一项服务,我必须登录本地管理员才能安装。当用户登录或注销以记录其用户名时,此服务的目的是记录。我终于找到了一些我认为可行的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();
为了澄清我的问题,我想要获得当前登录的用户,但是它给了我管理员我用来安装服务的帐户。
答案 0 :(得分:4)
您应该使用服务控制管理器通知。您可以将服务配置为在用户登录和/或注销时接收通知事件。这允许服务在服务需要时进行交互式用户模拟,但它应该为您提供日志记录所需的信息。
在此处查看“使用服务控制管理器(SCM)通知”部分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;
}
}
答案 1 :(得分:2)
这是我的代码(所有代码都驻留在一个类中;在我的例子中,类继承了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;
}
使用上面的代码,你可以简单地获取你所覆盖的方法中的用户名:
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
string username = GetUsername(changeDescription.SessionId);
//continue with any other thing you wish to do
}
答案 2 :(得分:1)
尝试更改插入sessionId参数的Account()方法并将changeDescription.SessionId传递给方法WTSQueryUserToken
public static string Account(uint sessionId)
{
IntPtr token = IntPtr.Zero;
String account = String.Empty;
if (WTSQueryUserToken(sessionId, out token))
{
...
...
p.s。:使用LocalSystem帐户运行您的服务
答案 3 :(得分:0)
我知道这个帖子已经老了,但是如果有人需要知道它是如何运作的:
添加对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;
}
}
现在您获得了user
中的用户名。如果计算机位于域中,则显示为domain\username