gpt4 book ai didi

c# - 从服务中注销 Windows 中的交互式用户

转载 作者:可可西里 更新时间:2023-11-01 08:21:07 24 4
gpt4 key购买 nike

我正在尝试找出一种方法,从用 C# 编写的 Windows 服务注销本地 Windows session 中的用户。

这是问题的背景:我需要管理一组用户的电脑使用时间;当他们分配的时间到期时,我想将他们注销。这是在 W2K8 域的上下文中。不幸的是,Windows 中的登录时间控件只会断开用户与服务器资源的连接;无法通过此方法强制他们的 session 终止。

我的方法是构建一个我将跨域部署的 Windows 服务;该服务将在每台客户端计算机上运行。该服务将定期枚举计算机上的登录用户,调用数据库以将自上次调用以来的登录时间添加到当天的总计中,如果已达到最大值,则将其注销(五分钟警告)。注意 - 这些不是终端服务 session ,它们是常规的本地交互式登录。另请注意,由于 Win7 和 Vista 中的“切换用户”功能,一台机器上可能会有多个登录。我所有的客户端电脑都将运行 Win7。 Windows 服务将作为本地系统运行,因此权限应该不是问题。

我可以使用 WMI 按用户名在机器上成功构建登录用户列表。这是该代码的一个片段:


        List<string> loggedInUsers = new List<string>();
ManagementClass mc = new ManagementClass("Win32_Process");
ManagementObjectCollection moc = mc.GetInstances();

foreach (ManagementObject mo in moc)
{
ROOT.CIMV2.Process process = new ROOT.CIMV2.Process(mo);
string domain, user;
uint pid;
process.GetOwner(out domain, out user);
pid = process.ProcessId;
if (process.Name.Trim().ToLower() == "explorer.exe")
loggedInUsers.Add(user);
}
return loggedInUsers;

但是,我正在努力寻找一种允许我注销选定用户 session 的方法。我知道我可以关闭机器,但我不想这样做 - 这会终止所有用户的 session 。

有什么想法吗?感谢您阅读这篇冗长的文章!

最佳答案

您可以使用以下 P/Invoke 调用来实现此目的。 以下示例仅适用于管理员权限

        [DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSLogoffSession(IntPtr hServer, int SessionId, bool bWait);

[DllImport("Wtsapi32.dll")]
static extern bool WTSQuerySessionInformation(
System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);

[DllImport("wtsapi32.dll", SetLastError = true)]
static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

[DllImport("wtsapi32.dll")]
static extern void WTSCloseServer(IntPtr hServer);

[DllImport("wtsapi32.dll", SetLastError = true)]
static extern Int32 WTSEnumerateSessions(IntPtr hServer, [MarshalAs(UnmanagedType.U4)] Int32 Reserved, [MarshalAs(UnmanagedType.U4)] Int32 Version, ref IntPtr ppSessionInfo, [MarshalAs(UnmanagedType.U4)] ref Int32 pCount);

[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pMemory);

这是一个示例实现,用于查找所有用户及其 session ,然后注销其中一个用户。

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
[StructLayout(LayoutKind.Sequential)]
internal struct WTS_SESSION_INFO
{
public Int32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public String pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}

internal enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}

internal enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
WTSIdleTime,
WTSLogonTime,
WTSIncomingBytes,
WTSOutgoingBytes,
WTSIncomingFrames,
WTSOutgoingFrames,
WTSClientInfo,
WTSSessionInfo
}

class Program
{
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSLogoffSession(IntPtr hServer, int SessionId, bool bWait);

[DllImport("Wtsapi32.dll")]
static extern bool WTSQuerySessionInformation(
System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);

[DllImport("wtsapi32.dll", SetLastError = true)]
static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

[DllImport("wtsapi32.dll")]
static extern void WTSCloseServer(IntPtr hServer);

[DllImport("wtsapi32.dll", SetLastError = true)]
static extern Int32 WTSEnumerateSessions(IntPtr hServer, [MarshalAs(UnmanagedType.U4)] Int32 Reserved, [MarshalAs(UnmanagedType.U4)] Int32 Version, ref IntPtr ppSessionInfo, [MarshalAs(UnmanagedType.U4)] ref Int32 pCount);

[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pMemory);

internal static List<int> GetSessionIDs(IntPtr server)
{
List<int> sessionIds = new List<int>();
IntPtr buffer = IntPtr.Zero;
int count = 0;
int retval = WTSEnumerateSessions(server, 0, 1, ref buffer, ref count);
int dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
Int64 current = (int)buffer;

if (retval != 0)
{
for (int i = 0; i < count; i++)
{
WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
current += dataSize;
sessionIds.Add(si.SessionID);
}
WTSFreeMemory(buffer);
}
return sessionIds;
}

internal static bool LogOffUser(string userName, IntPtr server)
{

userName = userName.Trim().ToUpper();
List<int> sessions = GetSessionIDs(server);
Dictionary<string, int> userSessionDictionary = GetUserSessionDictionary(server, sessions);
if (userSessionDictionary.ContainsKey(userName))
return WTSLogoffSession(server, userSessionDictionary[userName], true);
else
return false;
}

private static Dictionary<string, int> GetUserSessionDictionary(IntPtr server, List<int> sessions)
{
Dictionary<string, int> userSession = new Dictionary<string, int>();

foreach (var sessionId in sessions)
{
string uName = GetUserName(sessionId, server);
if (!string.IsNullOrWhiteSpace(uName))
userSession.Add(uName, sessionId);
}
return userSession;
}

internal static string GetUserName(int sessionId, IntPtr server)
{
IntPtr buffer = IntPtr.Zero;
uint count = 0;
string userName = string.Empty;
try
{
WTSQuerySessionInformation(server, sessionId, WTS_INFO_CLASS.WTSUserName, out buffer, out count);
userName = Marshal.PtrToStringAnsi(buffer).ToUpper().Trim();
}
finally
{
WTSFreeMemory(buffer);
}
return userName;
}

static void Main(string[] args)
{
string input = string.Empty;
Console.Write("Enter ServerName<Enter 0 to default to local>:");
input = Console.ReadLine();
IntPtr server = WTSOpenServer(input.Trim()[0] == '0' ? Environment.MachineName : input.Trim());
try
{
do
{
Console.WriteLine("Please Enter L => list sessions, G => Logoff a user, END => exit.");
input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
continue;
else if (input.ToUpper().Trim()[0] == 'L')
{
Dictionary<string, int> userSessionDict = GetUserSessionDictionary(server, GetSessionIDs(server));
foreach (var userSession in userSessionDict)
{
Console.WriteLine(string.Format("{0} is logged in {1} session", userSession.Key, userSession.Value));
}
}
else if (input.ToUpper().Trim()[0] == 'G')
{
Console.Write("Enter UserName:");
input = Console.ReadLine();
LogOffUser(input, server);
}

} while (input.ToUpper() != "END");
}
finally
{
WTSCloseServer(server);
}
}
}
}

关于c# - 从服务中注销 Windows 中的交互式用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5207506/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com