业务场景:
客户有这么个需求,有几个IRM插件4Office、4Adobe 和Jre安装的软件,需要在业务部门的客户端安装,但是这些客户端是AD域中的普通用户(Domain Users组中的用户,也不是本地管理员)没有权限安装软件,现在软件放在一台文件共享服务器上,用户也没有访问这台文件共享服务器的权限,需要做一个Winform程序,来完成安装这些软件的功能。用户只给提供一个用户:admin1 此用户在AD域中属于Domain Admins组
思路:
思路很简单,总共分两步:
但是在这个过程中遇到了以下问题:
这里用了P/Invoke 本来模拟用户登录计算机是打算 同过两个步骤来完成的:
先通过:模拟用户登录
[DllImport("advapi32.dll", SetLastError = true)] public static extern bool LogonUser( string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken );
然后在LoadUserProfile
1 [DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)] 2 private static extern bool LoadUserProfile(IntPtr hToken, ref ProfileInfo lpProfileInfo);
但是这种方法存在问题,如果是本地用户的话就回work,但是如果是domain 里的用户,没有显示加入本地计算机中的话,无论如何也不能生成User Profile,最后发现:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern Boolean CreateProcessWithLogonW ( String lpszUsername, String lpszDomain, String lpszPassword, Int32 dwLogonFlags, String applicationName, String commandLine, Int32 creationFlags, IntPtr environment, String currentDirectory, ref STARTUPINFO sui, out PROCESS_INFORMATION processInfo );
这个方法完全就可以满足要求,这个方法里的dwLogonFlags参数可以指定登陆的时候生成User Profile 解决了我的大问题。
主要代码如下:
1 public class UNCAccess 2 { 3 [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 4 internal struct USE_INFO_2 5 { 6 internal LMSTR ui2_local; 7 internal LMSTR ui2_remote; 8 internal LMSTR ui2_password; 9 internal DWORD ui2_status; 10 internal DWORD ui2_asg_type; 11 internal DWORD ui2_refcount; 12 internal DWORD ui2_usecount; 13 internal LPWSTR ui2_username; 14 internal LMSTR ui2_domainname; 15 } 16 17 [DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 18 internal static extern UInt32 NetUseAdd( 19 String UncServerName, 20 UInt32 Level, 21 ref USE_INFO_2 Buf, 22 out UInt32 ParmError); 23 24 [DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 25 internal static extern UInt32 NetUseDel( 26 String UncServerName, 27 String UseName, 28 UInt32 ForceCond); 29 30 private string sUNCPath; 31 private string sUser; 32 private string sPassword; 33 private string sDomain; 34 private int iLastError; 35 36 public UNCAccess() 37 { 38 } 39 40 public UNCAccess(string UNCPath, string User, string Domain, string Password) 41 { 42 login(UNCPath, User, Domain, Password); 43 } 44 45 public int LastError 46 { 47 get { return iLastError; } 48 } 49 50 /// <summary> 51 /// Connects to a UNC share folder with credentials 52 /// </summary> 53 /// <param name="UNCPath">UNC share path</param> 54 /// <param name="User">Username</param> 55 /// <param name="Domain">Domain</param> 56 /// <param name="Password">Password</param> 57 /// <returns>True if login was successful</returns> 58 public Boolean login(string UNCPath, string User, string Domain, string Password) 59 { 60 sUNCPath = UNCPath; 61 sUser = User; 62 sPassword = Password; 63 sDomain = Domain; 64 return NetUseWithCredentials(); 65 } 66 67 private Boolean NetUseWithCredentials() 68 { 69 uint returncode; 70 try 71 { 72 USE_INFO_2 useinfo = new USE_INFO_2(); 73 74 useinfo.ui2_remote = sUNCPath; 75 useinfo.ui2_username = sUser; 76 useinfo.ui2_domainname = sDomain; 77 useinfo.ui2_password = sPassword; 78 useinfo.ui2_asg_type = 0; 79 useinfo.ui2_usecount = 1; 80 uint paramErrorIndex; 81 returncode = NetUseAdd(null, 2, ref useinfo, out paramErrorIndex); 82 iLastError = (int)returncode; 83 return returncode == 0; 84 } 85 catch 86 { 87 iLastError = Marshal.GetLastWin32Error(); 88 return false; 89 } 90 } 91 92 /// <summary> 93 /// Closes the UNC share 94 /// </summary> 95 /// <returns>True if closing was successful</returns> 96 public Boolean NetUseDelete() 97 { 98 uint returncode; 99 try 100 { 101 returncode = NetUseDel(null, sUNCPath, 2); 102 iLastError = (int)returncode; 103 return (returncode == 0); 104 } 105 catch 106 { 107 iLastError = Marshal.GetLastWin32Error(); 108 return false; 109 } 110 } 111 }
1 public class ProcessManager 2 { 3 const UInt32 INFINITE = 0xFFFFFFFF; 4 const UInt32 WAIT_FAILED = 0xFFFFFFFF; 5 6 7 [Flags] 8 public enum LogonType 9 { 10 LOGON32_LOGON_INTERACTIVE = 2, 11 LOGON32_LOGON_NETWORK = 3, 12 LOGON32_LOGON_BATCH = 4, 13 LOGON32_LOGON_SERVICE = 5, 14 LOGON32_LOGON_UNLOCK = 7, 15 LOGON32_LOGON_NETWORK_CLEARTEXT = 8, 16 LOGON32_LOGON_NEW_CREDENTIALS = 9 17 } 18 19 [Flags] 20 public enum LogonProvider 21 { 22 LOGON32_PROVIDER_DEFAULT = 0, 23 LOGON32_PROVIDER_WINNT35, 24 LOGON32_PROVIDER_WINNT40, 25 LOGON32_PROVIDER_WINNT50 26 } 27 28 [Flags] 29 public enum LogonFlags 30 { 31 LOGON_WITH_PROFILE = 1, 32 LOGON_NETCREDENTIALS_ONLY =2 33 } 34 35 [StructLayout(LayoutKind.Sequential)] 36 public struct STARTUPINFO 37 { 38 public Int32 cb; 39 public String lpReserved; 40 public String lpDesktop; 41 public String lpTitle; 42 public Int32 dwX; 43 public Int32 dwY; 44 public Int32 dwXSize; 45 public Int32 dwYSize; 46 public Int32 dwXCountChars; 47 public Int32 dwYCountChars; 48 public Int32 dwFillAttribute; 49 public Int32 dwFlags; 50 public Int16 wShowWindow; 51 public Int16 cbReserved2; 52 public IntPtr lpReserved2; 53 public IntPtr hStdInput; 54 public IntPtr hStdOutput; 55 public IntPtr hStdError; 56 } 57 58 [StructLayout(LayoutKind.Sequential)] 59 public struct PROCESS_INFORMATION 60 { 61 public IntPtr hProcess; 62 public IntPtr hThread; 63 public Int32 dwProcessId; 64 public Int32 dwThreadId; 65 } 66 67 [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 68 public static extern Boolean LogonUser 69 ( 70 String lpszUserName, 71 String lpszDomain, 72 String lpszPassword, 73 LogonType dwLogonType, 74 LogonProvider dwLogonProvider, 75 out IntPtr phToken 76 ); 77 78 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 79 public static extern Boolean CreateProcessAsUser 80 ( 81 IntPtr hToken, 82 String lpApplicationName, 83 String lpCommandLine, 84 IntPtr lpProcessAttributes, 85 IntPtr lpThreadAttributes, 86 Boolean bInheritHandles, 87 Int32 dwCreationFlags, 88 IntPtr lpEnvironment, 89 String lpCurrentDirectory, 90 ref STARTUPINFO lpStartupInfo, 91 out PROCESS_INFORMATION lpProcessInformation 92 ); 93 94 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 95 public static extern Boolean CreateProcessWithLogonW 96 ( 97 String lpszUsername, 98 String lpszDomain, 99 String lpszPassword, 100 Int32 dwLogonFlags, 101 String applicationName, 102 String commandLine, 103 Int32 creationFlags, 104 IntPtr environment, 105 String currentDirectory, 106 ref STARTUPINFO sui, 107 out PROCESS_INFORMATION processInfo 108 ); 109 110 [DllImport("kernel32.dll", SetLastError = true)] 111 public static extern UInt32 WaitForSingleObject 112 ( 113 IntPtr hHandle, 114 UInt32 dwMilliseconds 115 ); 116 117 [DllImport("kernel32", SetLastError = true)] 118 public static extern Boolean CloseHandle(IntPtr handle); 119 120 121 public static void LaunchCommand1(string strCommand,string applicationName, string strDomain, string strName, string strPassword) 122 { 123 // Variables 124 PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION(); 125 STARTUPINFO startInfo = new STARTUPINFO(); 126 bool bResult = false; 127 UInt32 uiResultWait = WAIT_FAILED; 128 129 try 130 { 131 // Create process 132 startInfo.cb = Marshal.SizeOf(startInfo); 133 134 bResult = CreateProcessWithLogonW( 135 strName, 136 strDomain, 137 strPassword, 138 (int)LogonFlags.LOGON_WITH_PROFILE, 139 applicationName, 140 strCommand, 141 0, 142 IntPtr.Zero, 143 null, 144 ref startInfo, 145 out processInfo 146 ); 147 if (!bResult) { throw new Exception("CreateProcessWithLogonW error #" + Marshal.GetLastWin32Error().ToString()); } 148 149 // Wait for process to end 150 uiResultWait = WaitForSingleObject(processInfo.hProcess, INFINITE); 151 if (uiResultWait == WAIT_FAILED) { throw new Exception("WaitForSingleObject error #" + Marshal.GetLastWin32Error()); } 152 153 } 154 finally 155 { 156 // Close all handles 157 CloseHandle(processInfo.hProcess); 158 CloseHandle(processInfo.hThread); 159 } 160 } 161 }