获取模拟进程的Windows用户

时间:2014-08-13 15:24:26

标签: c# impersonation

我正在另一个用户下使用C#应用程序中的CreateProcessWithLogonW方法创建一个新进程,该应用程序用作启动程序。在模拟过程中(也用C#编写),我需要获取登录到Windows的原始用户的用户名(而不是被模拟的用户的用户名)。这不是ASP应用程序。我怎么能做到这一点?

2 个答案:

答案 0 :(得分:0)

您可以使用P / Invoke获取当前登录用户的列表。请记住,在Windows中,一次可以有多个人登录到计算机。您必须枚举列表并选择适当的用户。

P/Invoke for NetWkstaUserEnum function

[DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
    static extern int NetWkstaUserEnum(
       string servername,
       int level,
       out IntPtr bufptr,
       int prefmaxlen,
       out int entriesread,
       out int totalentries,
       ref int resume_handle);

答案 1 :(得分:0)

我最终在以下帮助器类中使用了'GetWindowsSessionUsername'方法,该方法从进程ID获取会话ID,从会话ID获取用户名。

internal class WtsUtils
{
    /// <summary>
    /// Contains values that indicate the type of session information to retrieve in a call to the <see cref="WTSQuerySessionInformation"/> function.
    /// </summary>
    private enum WtsInfoClass
    {
        /// <summary>A null-terminated string that contains the name of the initial program that Remote Desktop Services runs when the user logs on.</summary>
        WtsInitialProgram,
        /// <summary>A null-terminated string that contains the published name of the application that the session is running.</summary>
        WtsApplicationName,

        /// <summary>A null-terminated string that contains the default directory used when launching the initial program.</summary>
        WtsWorkingDirectory,

        /// <summary>This value is not used.</summary>
        WtsOemId,

        /// <summary>A <B>ULONG</B> value that contains the session identifier.</summary>
       WtsSessionId,

        /// <summary>A null-terminated string that contains the name of the user associated with the session.</summary>
       WtsUserName,

        /// <summary>A null-terminated string that contains the name of the Remote Desktop Services session.</summary>
        /// <remarks>
        /// <B>Note</B>  Despite its name, specifying this type does not return the window station name.
        /// Rather, it returns the name of the Remote Desktop Services session.
        /// Each Remote Desktop Services session is associated with an interactive window station.
        /// Because the only supported window station name for an interactive window station is "WinSta0",
        /// each session is associated with its own "WinSta0" window station. For more information, see <see href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms687096(v=vs.85).aspx">Window Stations</see>.
        /// </remarks>
        WtsWinStationName,

        /// <summary>A null-terminated string that contains the name of the domain to which the logged-on user belongs.</summary>
        WtsDomainName,

        /// <summary>The session's current connection state. For more information, see WTS_CONNECTSTATE_CLASS.</summary>
        WtsConnectState,

        /// <summary>A <B>ULONG</B> value that contains the build number of the client.</summary>
        WtsClientBuildNumber,

        /// <summary>A null-terminated string that contains the name of the client.</summary>
        WtsClientName,

        /// <summary>A null-terminated string that contains the directory in which the client is installed.</summary>
        WtsClientDirectory,

        /// <summary>A <B>USHORT</B> client-specific product identifier.</summary>
        WtsClientProductId,

        /// <summary>
        /// A <B>ULONG</B> value that contains a client-specific hardware identifier. This option is reserved for future use.
        /// <see cref="WTSQuerySessionInformation" /> will always return a value of 0.
        /// </summary>
        WtsClientHardwareId,

        /// <summary>The network type and network address of the client. For more information, see WTS_CLIENT_ADDRESS.</summary>
        /// <remarks>
        /// The IP address is offset by two bytes from the start of the <B>Address</B> member of the WTS_CLIENT_ADDRESS structure.
        /// </remarks>
        WtsClientAddress,

        /// <summary>Information about the display resolution of the client. For more information, see WTS_CLIENT_DISPLAY.</summary>
        WtsClientDisplay,

        /// <summary>
        /// A USHORT value that specifies information about the protocol type for the session. This is one of the following values:<BR />
        /// 0 - The console session.<BR />
        /// 1 - This value is retained for legacy purposes.<BR />
        /// 2 - The RDP protocol.<BR />
        /// </summary>
        WtsClientProtocolType,

        /// <summary>
        /// This value returns <B>FALSE</B>. If you call Marshal.GetLastError to get extended error information, <B>GetLastError</B> returns <B>ERROR_NOT_SUPPORTED</B>.
        /// </summary>
        /// <remarks><B>Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not used.</remarks>
        WtsIdleTime,

        /// <summary>
        /// This value returns <B>FALSE</B>. If you call GetLastError to get extended error information, <B>GetLastError</B> returns <B>ERROR_NOT_SUPPORTED</B>.
        /// </summary>
        /// <remarks><B>Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not used.</remarks>
        WtsLogonTime,

        /// <summary>
        /// This value returns <B>FALSE</B>. If you call Marshal.GetLastError to get extended error information, <B>GetLastError</B> returns <B>ERROR_NOT_SUPPORTED</B>.
        /// </summary>
        /// <remarks><B>Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not used.</remarks>
        WtsIncomingBytes,

        /// <summary>
        /// This value returns <B>FALSE</B>. If you call Marshal.GetLastError to get extended error information, <B>GetLastError</B> returns <B>ERROR_NOT_SUPPORTED</B>.
        /// </summary>
        /// <remarks><B>Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not used.</remarks>
        WtsOutgoingBytes,

        /// <summary>
        /// This value returns <B>FALSE</B>. If you call Marshal.GetLastError to get extended error information, <B>GetLastError</B> returns <B>ERROR_NOT_SUPPORTED</B>.
        /// </summary>
        /// <remarks><B>Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not used.</remarks>
        WtsIncomingFrames,

        /// <summary>
        /// This value returns <B>FALSE</B>. If you call Marshal.GetLastError to get extended error information, <B>GetLastError</B> returns <B>ERROR_NOT_SUPPORTED</B>.
        /// </summary>
        /// <remarks><B>Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not used.</remarks>
        WtsOutgoingFrames,

        /// <summary>Information about a Remote Desktop Connection (RDC) client. For more information, see WTSCLIENT.</summary>
        /// <remarks>
        /// <B>Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not supported.
        /// This value is supported beginning with Windows Server 2008 and Windows Vista with SP1.
        /// </remarks>
        WtsClientInfo,

        /// <summary>Information about a client session on an RD Session Host server. For more information, see WTSINFO.</summary>
        /// <remarks>
        /// <B>Windows Vista, Windows Server 2003, and Windows XP:</B>  This value is not supported.
        /// This value is supported beginning with Windows Server 2008 and Windows Vista with SP1.
        /// </remarks>
        WtsSessionInfo
    }

    [DllImport("kernel32.dll")]
    private static extern bool ProcessIdToSessionId(uint dwProcessId, out uint sessionId);

    [DllImport("Wtsapi32.dll")]
    private static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WtsInfoClass wtsInfoClass, out IntPtr ppBuffer, out int bytesReturned);

    [DllImport("Wtsapi32.dll")]
    private static extern void WTSFreeMemory(IntPtr pointer);

    public static string GetWindowsSessionUsername()
    {
        uint sessionId;
        ProcessIdToSessionId((uint)Process.GetCurrentProcess().Id, out sessionId);

        return GetUsernameBySessionId((int)sessionId);
    }

    private static string GetUsernameBySessionId(int sessionId)
    {
        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);
        }
        return username;
    }
}