2017-03-10 21 views
1

我已经编写了此Powershell脚本以获取活动登录用户。 它运行在exe文件(C#)完美,当我从Powershell运行相同,我越来越Arithmetic operation resulted in an overflow.在Powershell中获取已登录的用户

找不到问题。有什么问题?

function IsUserCurrentlyLoggedIn($UserDomain, $UserName) 
{ 
    Add-Type -Language CSharp -TypeDefinition @' 
using System; 
using System.Runtime.InteropServices; 

namespace Test 
{ 
    public static class EnumerateUsers 
    { 
     [DllImport("wtsapi32.dll")] 
     static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName); 

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

     [DllImport("wtsapi32.dll")] 
     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); 

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

     [StructLayout(LayoutKind.Sequential)] 
     private struct WTS_SESSION_INFO 
     { 
      public Int32 SessionID; 

      [MarshalAs(UnmanagedType.LPStr)] 
      public String pWinStationName; 

      public WTS_CONNECTSTATE_CLASS State; 
     } 

     public enum WTS_INFO_CLASS 
     { 
      WTSInitialProgram, 
      WTSApplicationName, 
      WTSWorkingDirectory, 
      WTSOEMId, 
      WTSSessionId, 
      WTSUserName, 
      WTSWinStationName, 
      WTSDomainName, 
      WTSConnectState, 
      WTSClientBuildNumber, 
      WTSClientName, 
      WTSClientDirectory, 
      WTSClientProductId, 
      WTSClientHardwareId, 
      WTSClientAddress, 
      WTSClientDisplay, 
      WTSClientProtocolType 
     } 
     public enum WTS_CONNECTSTATE_CLASS 
     { 
      WTSActive, 
      WTSConnected, 
      WTSConnectQuery, 
      WTSShadow, 
      WTSDisconnected, 
      WTSIdle, 
      WTSListen, 
      WTSReset, 
      WTSDown, 
      WTSInit 
     } 

     public static IntPtr OpenServer(String Name) 
     { 
      IntPtr server = WTSOpenServer(Name); 
      return server; 
     } 
     public static void CloseServer(IntPtr ServerHandle) 
     { 
      WTSCloseServer(ServerHandle); 
     } 
     public static bool IsActiveSessionExists(string UserDomain, string Username) 
     { 
      IntPtr serverHandle = IntPtr.Zero; 
      serverHandle = OpenServer(Environment.MachineName); 
      IntPtr SessionInfoPtr = IntPtr.Zero; 

      try 
      { 
       IntPtr userPtr = IntPtr.Zero; 
       IntPtr domainPtr = IntPtr.Zero; 
       Int32 sessionCount = 0; 
       Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref sessionCount); 
       Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO)); 
       Int32 currentSession = (int)SessionInfoPtr; 
       uint bytes = 0; 

       if (retVal != 0) 
       { 
        for (int i = 0; i < sessionCount; i++) 
        { 
         WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTS_SESSION_INFO)); 
         currentSession += dataSize; 

         WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSUserName, out userPtr, out bytes); 
         WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSDomainName, out domainPtr, out bytes); 

         var domain = Marshal.PtrToStringAnsi(domainPtr); 
         var username = Marshal.PtrToStringAnsi(userPtr); 

         if (UserDomain.Equals(domain, StringComparison.OrdinalIgnoreCase) && 
          Username.Equals(username, StringComparison.OrdinalIgnoreCase) && 
          si.State == WTS_CONNECTSTATE_CLASS.WTSActive) 
         { 
          WTSFreeMemory(userPtr); 
          WTSFreeMemory(domainPtr); 
          return true; 
         } 
         WTSFreeMemory(userPtr); 
         WTSFreeMemory(domainPtr); 
        } 
       } 
      } 
      finally 
      { 
       WTSFreeMemory(SessionInfoPtr); 
       CloseServer(serverHandle); 
      } 
      return false; 
     } 
    } 
} 
'@ 
    return [Test.EnumerateUsers]::IsActiveSessionExists($UserDomain, $UserName) 
} 

回答

5

我复制你的C#代码到一个Visual Studio 2015年项目,并发现禁用Prefer 32-bit或项目的Build性质改变Platform targetx64产生在这条线相同的异常:

Int32 currentSession = (int)SessionInfoPtr; 

IntPtr在32位进程中是32位,在64位进程中是64位,但是此代码假定它是32位的,因此可以转换为intInt32)。在64位Windows上,$Env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe的PowerShell的“默认”版本也是64位,您可以通过[IntPtr]::Size返回8(字节)的事实来确认。将代码更改为以下消除了64位C#项目和PowerShell中的异常:

IntPtr currentSession = SessionInfoPtr; 
+0

实际上,我刚刚修复了这个问题,令人惊讶的是您指出了相同:) – Reddy