How to know if a Windows session is an interactive one?

半城伤御伤魂 提交于 2020-01-23 12:08:11

问题


I'm creating a service that will run processes on user interactive session. I found how to start process from session 0 in a service, I found how to catch when a user is logged on.

But I need to know if a Windows session is an interactive one or the list of interactive Windows sessions.


回答1:


First setup your interop declarations. This is the hardest part

DllImport("secur32.dll", SetLastError = false)]
private static extern uint LsaFreeReturnBuffer(IntPtr buffer);

[DllImport("Secur32.dll", SetLastError = false)]
private static extern uint LsaEnumerateLogonSessions
        (out UInt64 LogonSessionCount, out IntPtr LogonSessionList);

[DllImport("Secur32.dll", SetLastError = false)]
private static extern uint LsaGetLogonSessionData(IntPtr luid, 
    out IntPtr ppLogonSessionData);

[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING
{
    public UInt16 Length;
    public UInt16 MaximumLength;
    public IntPtr buffer;
}

[StructLayout(LayoutKind.Sequential)]
private struct LUID
{
    public UInt32 LowPart;
    public UInt32 HighPart;
}

[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_LOGON_SESSION_DATA
{
    public UInt32 Size;
    public LUID LoginID;
    public LSA_UNICODE_STRING Username;
    public LSA_UNICODE_STRING LoginDomain;
    public LSA_UNICODE_STRING AuthenticationPackage;
    public UInt32 LogonType;
    public UInt32 Session;
    public IntPtr PSiD;
    public UInt64 LoginTime;
    public LSA_UNICODE_STRING LogonServer;
    public LSA_UNICODE_STRING DnsDomainName;
    public LSA_UNICODE_STRING Upn;
}

private enum SECURITY_LOGON_TYPE : uint
{
    Interactive = 2,        //The security principal is logging on 
                            //interactively.
    Network,                //The security principal is logging using a 
                            //network.
    Batch,                  //The logon is for a batch process.
    Service,                //The logon is for a service account.
    Proxy,                  //Not supported.
    Unlock,                 //The logon is an attempt to unlock a workstation.
    NetworkCleartext,       //The logon is a network logon with cleartext 
                            //credentials.
    NewCredentials,         //Allows the caller to clone its current token and
                            //specify new credentials for outbound connections.
    RemoteInteractive,      //A terminal server session that is both remote 
                            //and interactive.
    CachedInteractive,      //Attempt to use the cached credentials without 
                            //going out across the network.
    CachedRemoteInteractive,// Same as RemoteInteractive, except used 
                            // internally for auditing purposes.
    CachedUnlock            // The logon is an attempt to unlock a workstation.
}

Next Enumerate and extract the information

  UInt64 count;
  IntPtr luidPtr = IntPtr.Zero;
  LsaEnumerateLogonSessions(out count, out luidPtr);  //gets an array of 
                                                      //pointers to LUIDs

  IntPtr iter = luidPtr;                              //set the pointer to the
                                                      //start of the array

  for (ulong i = 0; i < count; i++)                   //for each pointer in the
                                                      //array
  {
      IntPtr sessionData;

      LsaGetLogonSessionData(iter, out sessionData);
      SECURITY_LOGON_SESSION_DATA data =(
          SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure
                (sessionData, typeof(SECURITY_LOGON_SESSION_DATA));

      //if we have a valid logon
      if (data.PSiD != IntPtr.Zero)
      {
          //get the security identifier for further use
          System.Security.Principal.SecurityIdentifier sid = 
          new System.Security.Principal.SecurityIdentifier(data.PSiD);

          SECURITY_LOGON_TYPE secType = (SECURITY_LOGON_TYPE)data.LogonType;

          //Look at sectype to see if interactive or remote interactive
          Console.WriteLine(secType.ToString())
          If (secType == SECURITY_LOGON_TYPE.Interactive || secType ==    SECURITY_LOGON_TYPE.RemoteInteractive)
          {
            //do something
          }

       }

       iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(LUID))); 
       //move the pointer forward
       LsaFreeReturnBuffer(sessionData);
       //free the SECURITY_LOGON_SESSION_DATA memory in the struct
  }
  LsaFreeReturnBuffer(luidPtr);       //free the array of LUIDs



回答2:


Use Environment.UserInteractive. It returns Boolean.




回答3:


In current versions of Windows, session 0 is the only non-interactive session. All other sessions are interactive, though they might or might not be connected to an interactive user at any given moment.

You can use WTSEnumerateSessions to determine what sessions exist and what state they are in.



来源:https://stackoverflow.com/questions/26910381/how-to-know-if-a-windows-session-is-an-interactive-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!