@@ -27,10 +27,11 @@ namespace PSCloudbase
27
27
{
28
28
const int LOGON32_LOGON_SERVICE = 5;
29
29
const int LOGON32_PROVIDER_DEFAULT = 0;
30
-
30
+ const int TOKEN_ALL_ACCESS = 0x000f01ff;
31
31
const uint GENERIC_ALL_ACCESS = 0x10000000;
32
-
33
32
const uint INFINITE = 0xFFFFFFFF;
33
+ const uint PI_NOUI = 0x00000001;
34
+ const uint WAIT_FAILED = 0xFFFFFFFF;
34
35
35
36
enum SECURITY_IMPERSONATION_LEVEL
36
37
{
@@ -86,6 +87,57 @@ namespace PSCloudbase
86
87
public IntPtr hStdError;
87
88
}
88
89
90
+ [StructLayout(LayoutKind.Sequential)]
91
+ struct PROFILEINFO {
92
+ public int dwSize;
93
+ public uint dwFlags;
94
+ [MarshalAs(UnmanagedType.LPTStr)]
95
+ public String lpUserName;
96
+ [MarshalAs(UnmanagedType.LPTStr)]
97
+ public String lpProfilePath;
98
+ [MarshalAs(UnmanagedType.LPTStr)]
99
+ public String lpDefaultPath;
100
+ [MarshalAs(UnmanagedType.LPTStr)]
101
+ public String lpServerName;
102
+ [MarshalAs(UnmanagedType.LPTStr)]
103
+ public String lpPolicyPath;
104
+ public IntPtr hProfile;
105
+ }
106
+
107
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
108
+ public struct USER_INFO_4
109
+ {
110
+ public string name;
111
+ public string password;
112
+ public int password_age;
113
+ public uint priv;
114
+ public string home_dir;
115
+ public string comment;
116
+ public uint flags;
117
+ public string script_path;
118
+ public uint auth_flags;
119
+ public string full_name;
120
+ public string usr_comment;
121
+ public string parms;
122
+ public string workstations;
123
+ public int last_logon;
124
+ public int last_logoff;
125
+ public int acct_expires;
126
+ public int max_storage;
127
+ public int units_per_week;
128
+ public IntPtr logon_hours; // This is a PBYTE
129
+ public int bad_pw_count;
130
+ public int num_logons;
131
+ public string logon_server;
132
+ public int country_code;
133
+ public int code_page;
134
+ public IntPtr user_sid; // This is a PSID
135
+ public int primary_group_id;
136
+ public string profile;
137
+ public string home_dir_drive;
138
+ public int password_expired;
139
+ }
140
+
89
141
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
90
142
extern static bool DuplicateTokenEx(
91
143
IntPtr hExistingToken,
@@ -133,14 +185,31 @@ namespace PSCloudbase
133
185
static extern bool GetExitCodeProcess(IntPtr hProcess,
134
186
out uint lpExitCode);
135
187
188
+ [DllImport("userenv.dll", SetLastError=true, CharSet=CharSet.Auto)]
189
+ [return: MarshalAs(UnmanagedType.Bool)]
190
+ static extern bool LoadUserProfile(IntPtr hToken,
191
+ ref PROFILEINFO lpProfileInfo);
192
+
193
+ [DllImport("userenv.dll", SetLastError=true, CharSet=CharSet.Auto)]
194
+ [return: MarshalAs(UnmanagedType.Bool)]
195
+ static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile);
196
+
197
+ [DllImport("Netapi32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
198
+ extern static int NetUserGetInfo(
199
+ [MarshalAs(UnmanagedType.LPWStr)] string ServerName,
200
+ [MarshalAs(UnmanagedType.LPWStr)] string UserName,
201
+ int level, out IntPtr BufPtr);
202
+
136
203
public static uint RunProcess(string userName, string password,
137
204
string domain, string cmd,
138
- string arguments)
205
+ string arguments,
206
+ bool loadUserProfile = true)
139
207
{
140
208
bool retValue;
141
209
IntPtr phToken = IntPtr.Zero;
142
210
IntPtr phTokenDup = IntPtr.Zero;
143
211
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
212
+ PROFILEINFO pi = new PROFILEINFO();
144
213
145
214
try
146
215
{
@@ -164,17 +233,35 @@ namespace PSCloudbase
164
233
STARTUPINFO sInfo = new STARTUPINFO();
165
234
sInfo.lpDesktop = "";
166
235
236
+ if(loadUserProfile)
237
+ {
238
+ IntPtr userInfoPtr = IntPtr.Zero;
239
+ int retValueNetUser = NetUserGetInfo(null, userName, 4,
240
+ out userInfoPtr);
241
+ if(retValueNetUser != 0)
242
+ throw new Win32Exception(retValueNetUser);
243
+
244
+ USER_INFO_4 userInfo = (USER_INFO_4)Marshal.PtrToStructure(
245
+ userInfoPtr, typeof(USER_INFO_4));
246
+
247
+ pi.dwSize = Marshal.SizeOf(pi);
248
+ pi.dwFlags = PI_NOUI;
249
+ pi.lpUserName = userName;
250
+ pi.lpProfilePath = userInfo.profile;
251
+
252
+ retValue = LoadUserProfile(phTokenDup, ref pi);
253
+ if(!retValue)
254
+ throw new Win32Exception(GetLastError());
255
+ }
256
+
167
257
retValue = CreateProcessAsUser(phTokenDup, cmd, arguments,
168
258
ref sa, ref sa, false, 0,
169
259
IntPtr.Zero, null,
170
260
ref sInfo, out pInfo);
171
261
if(!retValue)
172
262
throw new Win32Exception(GetLastError());
173
263
174
- WaitForSingleObject(pInfo.hProcess, INFINITE);
175
-
176
- var lastErr = GetLastError();
177
- if(lastErr != 0)
264
+ if(WaitForSingleObject(pInfo.hProcess, INFINITE) == WAIT_FAILED)
178
265
throw new Win32Exception(GetLastError());
179
266
180
267
uint exitCode;
@@ -186,6 +273,8 @@ namespace PSCloudbase
186
273
}
187
274
finally
188
275
{
276
+ if(pi.hProfile != IntPtr.Zero)
277
+ UnloadUserProfile(phTokenDup, pi.hProfile);
189
278
if(phToken != IntPtr.Zero)
190
279
CloseHandle(phToken);
191
280
if(phTokenDup != IntPtr.Zero)
@@ -212,7 +301,10 @@ function Start-ProcessAsUser
212
301
[string ]$Arguments ,
213
302
214
303
[parameter (Mandatory = $true )]
215
- [PSCredential ]$Credential
304
+ [PSCredential ]$Credential ,
305
+
306
+ [parameter ()]
307
+ [bool ]$LoadUserProfile = $true
216
308
)
217
309
process
218
310
{
@@ -226,6 +318,6 @@ function Start-ProcessAsUser
226
318
227
319
[PSCloudbase.ProcessManager ]::RunProcess($nc.UserName , $nc.Password ,
228
320
$domain , $Command ,
229
- $Arguments )
321
+ $Arguments , $LoadUserProfile )
230
322
}
231
323
}
0 commit comments