1 #!powershell
2
3 #AnsibleRequires -CSharpUtil Ansible.Basic
4 #AnsibleRequires -CSharpUtil Ansible.Become
5
6 $module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
7
Assert-Equalsnull8 Function Assert-Equals {
9 param(
10 [Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
11 [Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
12 )
13
14 $matched = $false
15 if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
16 $Actual.Count | Assert-Equals -Expected $Expected.Count
17 for ($i = 0; $i -lt $Actual.Count; $i++) {
18 $actual_value = $Actual[$i]
19 $expected_value = $Expected[$i]
20 Assert-Equals -Actual $actual_value -Expected $expected_value
21 }
22 $matched = $true
23 } else {
24 $matched = $Actual -ceq $Expected
25 }
26
27 if (-not $matched) {
28 if ($Actual -is [PSObject]) {
29 $Actual = $Actual.ToString()
30 }
31
32 $call_stack = (Get-PSCallStack)[1]
33 $module.Result.test = $test
34 $module.Result.actual = $Actual
35 $module.Result.expected = $Expected
36 $module.Result.line = $call_stack.ScriptLineNumber
37 $module.Result.method = $call_stack.Position.Text
38 $module.FailJson("AssertionError: actual != expected")
39 }
40 }
41
42 # Would be great to move win_whomai out into it's own module util and share the
43 # code here, for now just rely on a cut down version
44 $test_whoami = {
45 Add-Type -TypeDefinition @'
46 using Microsoft.Win32.SafeHandles;
47 using System;
48 using System.Runtime.ConstrainedExecution;
49 using System.Runtime.InteropServices;
50 using System.Security.Principal;
51 using System.Text;
52
53 namespace Ansible
54 {
55 internal class NativeHelpers
56 {
57 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
58 public struct LSA_UNICODE_STRING
59 {
60 public UInt16 Length;
61 public UInt16 MaximumLength;
62 public IntPtr Buffer;
63
64 public override string ToString()
65 {
66 return Marshal.PtrToStringUni(Buffer, Length / sizeof(char));
67 }
68 }
69
70 [StructLayout(LayoutKind.Sequential)]
71 public struct LUID
72 {
73 public UInt32 LowPart;
74 public Int32 HighPart;
75
76 public static explicit operator UInt64(LUID l)
77 {
78 return (UInt64)((UInt64)l.HighPart << 32) | (UInt64)l.LowPart;
79 }
80 }
81
82 [StructLayout(LayoutKind.Sequential)]
83 public struct SECURITY_LOGON_SESSION_DATA
84 {
85 public UInt32 Size;
86 public LUID LogonId;
87 public LSA_UNICODE_STRING UserName;
88 public LSA_UNICODE_STRING LogonDomain;
89 public LSA_UNICODE_STRING AuthenticationPackage;
90 public SECURITY_LOGON_TYPE LogonType;
91 }
92
93 [StructLayout(LayoutKind.Sequential)]
94 public struct SID_AND_ATTRIBUTES
95 {
96 public IntPtr Sid;
97 public int Attributes;
98 }
99
100 [StructLayout(LayoutKind.Sequential)]
101 public struct TOKEN_MANDATORY_LABEL
102 {
103 public SID_AND_ATTRIBUTES Label;
104 }
105
106 [StructLayout(LayoutKind.Sequential)]
107 public struct TOKEN_SOURCE
108 {
109 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public char[] SourceName;
110 public LUID SourceIdentifier;
111 }
112
113 [StructLayout(LayoutKind.Sequential)]
114 public struct TOKEN_STATISTICS
115 {
116 public LUID TokenId;
117 public LUID AuthenticationId;
118 }
119
120 [StructLayout(LayoutKind.Sequential)]
121 public struct TOKEN_USER
122 {
123 public SID_AND_ATTRIBUTES User;
124 }
125
126 public enum SECURITY_LOGON_TYPE
127 {
128 System = 0, // Used only by the Sytem account
129 Interactive = 2,
130 Network,
131 Batch,
132 Service,
133 Proxy,
134 Unlock,
135 NetworkCleartext,
136 NewCredentials,
137 RemoteInteractive,
138 CachedInteractive,
139 CachedRemoteInteractive,
140 CachedUnlock
141 }
142
143 public enum TokenInformationClass
144 {
145 TokenUser = 1,
146 TokenSource = 7,
147 TokenStatistics = 10,
148 TokenIntegrityLevel = 25,
149 }
150 }
151
152 internal class NativeMethods
153 {
154 [DllImport("kernel32.dll", SetLastError = true)]
155 public static extern bool CloseHandle(
156 IntPtr hObject);
157
158 [DllImport("kernel32.dll")]
159 public static extern SafeNativeHandle GetCurrentProcess();
160
161 [DllImport("userenv.dll", SetLastError = true)]
162 public static extern bool GetProfileType(
163 out UInt32 dwFlags);
164
165 [DllImport("advapi32.dll", SetLastError = true)]
166 public static extern bool GetTokenInformation(
167 SafeNativeHandle TokenHandle,
168 NativeHelpers.TokenInformationClass TokenInformationClass,
169 SafeMemoryBuffer TokenInformation,
170 UInt32 TokenInformationLength,
171 out UInt32 ReturnLength);
172
173 [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
174 public static extern bool LookupAccountSid(
175 string lpSystemName,
176 IntPtr Sid,
177 StringBuilder lpName,
178 ref UInt32 cchName,
179 StringBuilder ReferencedDomainName,
180 ref UInt32 cchReferencedDomainName,
181 out UInt32 peUse);
182
183 [DllImport("secur32.dll", SetLastError = true)]
184 public static extern UInt32 LsaEnumerateLogonSessions(
185 out UInt32 LogonSessionCount,
186 out SafeLsaMemoryBuffer LogonSessionList);
187
188 [DllImport("secur32.dll", SetLastError = true)]
189 public static extern UInt32 LsaFreeReturnBuffer(
190 IntPtr Buffer);
191
192 [DllImport("secur32.dll", SetLastError = true)]
193 public static extern UInt32 LsaGetLogonSessionData(
194 IntPtr LogonId,
195 out SafeLsaMemoryBuffer ppLogonSessionData);
196
197 [DllImport("advapi32.dll")]
198 public static extern UInt32 LsaNtStatusToWinError(
199 UInt32 Status);
200
201 [DllImport("advapi32.dll", SetLastError = true)]
202 public static extern bool OpenProcessToken(
203 SafeNativeHandle ProcessHandle,
204 TokenAccessLevels DesiredAccess,
205 out SafeNativeHandle TokenHandle);
206 }
207
208 internal class SafeLsaMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
209 {
210 public SafeLsaMemoryBuffer() : base(true) { }
211
212 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
213 protected override bool ReleaseHandle()
214 {
215 UInt32 res = NativeMethods.LsaFreeReturnBuffer(handle);
216 return res == 0;
217 }
218 }
219
220 internal class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
221 {
222 public SafeMemoryBuffer() : base(true) { }
223 public SafeMemoryBuffer(int cb) : base(true)
224 {
225 base.SetHandle(Marshal.AllocHGlobal(cb));
226 }
227 public SafeMemoryBuffer(IntPtr handle) : base(true)
228 {
229 base.SetHandle(handle);
230 }
231
232 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
233 protected override bool ReleaseHandle()
234 {
235 Marshal.FreeHGlobal(handle);
236 return true;
237 }
238 }
239
240 internal class SafeNativeHandle : SafeHandleZeroOrMinusOneIsInvalid
241 {
242 public SafeNativeHandle() : base(true) { }
243 public SafeNativeHandle(IntPtr handle) : base(true) { this.handle = handle; }
244
245 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
246 protected override bool ReleaseHandle()
247 {
248 return NativeMethods.CloseHandle(handle);
249 }
250 }
251
252 public class Win32Exception : System.ComponentModel.Win32Exception
253 {
254 private string _msg;
255
256 public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
257 public Win32Exception(int errorCode, string message) : base(errorCode)
258 {
259 _msg = String.Format("{0} ({1}, Win32ErrorCode {2})", message, base.Message, errorCode);
260 }
261
262 public override string Message { get { return _msg; } }
263 public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
264 }
265
266 public class Logon
267 {
268 public string AuthenticationPackage { get; internal set; }
269 public string LogonType { get; internal set; }
270 public string MandatoryLabelName { get; internal set; }
271 public SecurityIdentifier MandatoryLabelSid { get; internal set; }
272 public bool ProfileLoaded { get; internal set; }
273 public string SourceName { get; internal set; }
274 public string UserName { get; internal set; }
275 public SecurityIdentifier UserSid { get; internal set; }
276
277 public Logon()
278 {
279 using (SafeNativeHandle process = NativeMethods.GetCurrentProcess())
280 {
281 TokenAccessLevels dwAccess = TokenAccessLevels.Query | TokenAccessLevels.QuerySource;
282
283 SafeNativeHandle hToken;
284 NativeMethods.OpenProcessToken(process, dwAccess, out hToken);
285 using (hToken)
286 {
287 SetLogonSessionData(hToken);
288 SetTokenMandatoryLabel(hToken);
289 SetTokenSource(hToken);
290 SetTokenUser(hToken);
291 }
292 }
293 SetProfileLoaded();
294 }
295
296 private void SetLogonSessionData(SafeNativeHandle hToken)
297 {
298 NativeHelpers.TokenInformationClass tokenClass = NativeHelpers.TokenInformationClass.TokenStatistics;
299 UInt32 returnLength;
300 NativeMethods.GetTokenInformation(hToken, tokenClass, new SafeMemoryBuffer(IntPtr.Zero), 0, out returnLength);
301
302 UInt64 tokenLuidId;
303 using (SafeMemoryBuffer infoPtr = new SafeMemoryBuffer((int)returnLength))
304 {
305 if (!NativeMethods.GetTokenInformation(hToken, tokenClass, infoPtr, returnLength, out returnLength))
306 throw new Win32Exception("GetTokenInformation(TokenStatistics) failed");
307
308 NativeHelpers.TOKEN_STATISTICS stats = (NativeHelpers.TOKEN_STATISTICS)Marshal.PtrToStructure(
309 infoPtr.DangerousGetHandle(), typeof(NativeHelpers.TOKEN_STATISTICS));
310 tokenLuidId = (UInt64)stats.AuthenticationId;
311 }
312
313 UInt32 sessionCount;
314 SafeLsaMemoryBuffer sessionPtr;
315 UInt32 res = NativeMethods.LsaEnumerateLogonSessions(out sessionCount, out sessionPtr);
316 if (res != 0)
317 throw new Win32Exception((int)NativeMethods.LsaNtStatusToWinError(res), "LsaEnumerateLogonSession() failed");
318 using (sessionPtr)
319 {
320 IntPtr currentSession = sessionPtr.DangerousGetHandle();
321 for (UInt32 i = 0; i < sessionCount; i++)
322 {
323 SafeLsaMemoryBuffer sessionDataPtr;
324 res = NativeMethods.LsaGetLogonSessionData(currentSession, out sessionDataPtr);
325 if (res != 0)
326 {
327 currentSession = IntPtr.Add(currentSession, Marshal.SizeOf(typeof(NativeHelpers.LUID)));
328 continue;
329 }
330 using (sessionDataPtr)
331 {
332 NativeHelpers.SECURITY_LOGON_SESSION_DATA sessionData = (NativeHelpers.SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(
333 sessionDataPtr.DangerousGetHandle(), typeof(NativeHelpers.SECURITY_LOGON_SESSION_DATA));
334 UInt64 sessionId = (UInt64)sessionData.LogonId;
335 if (sessionId == tokenLuidId)
336 {
337 AuthenticationPackage = sessionData.AuthenticationPackage.ToString();
338 LogonType = sessionData.LogonType.ToString();
339 break;
340 }
341 }
342
343 currentSession = IntPtr.Add(currentSession, Marshal.SizeOf(typeof(NativeHelpers.LUID)));
344 }
345 }
346 }
347
348 private void SetTokenMandatoryLabel(SafeNativeHandle hToken)
349 {
350 NativeHelpers.TokenInformationClass tokenClass = NativeHelpers.TokenInformationClass.TokenIntegrityLevel;
351 UInt32 returnLength;
352 NativeMethods.GetTokenInformation(hToken, tokenClass, new SafeMemoryBuffer(IntPtr.Zero), 0, out returnLength);
353 using (SafeMemoryBuffer infoPtr = new SafeMemoryBuffer((int)returnLength))
354 {
355 if (!NativeMethods.GetTokenInformation(hToken, tokenClass, infoPtr, returnLength, out returnLength))
356 throw new Win32Exception("GetTokenInformation(TokenIntegrityLevel) failed");
357 NativeHelpers.TOKEN_MANDATORY_LABEL label = (NativeHelpers.TOKEN_MANDATORY_LABEL)Marshal.PtrToStructure(
358 infoPtr.DangerousGetHandle(), typeof(NativeHelpers.TOKEN_MANDATORY_LABEL));
359 MandatoryLabelName = LookupSidName(label.Label.Sid);
360 MandatoryLabelSid = new SecurityIdentifier(label.Label.Sid);
361 }
362 }
363
364 private void SetTokenSource(SafeNativeHandle hToken)
365 {
366 NativeHelpers.TokenInformationClass tokenClass = NativeHelpers.TokenInformationClass.TokenSource;
367 UInt32 returnLength;
368 NativeMethods.GetTokenInformation(hToken, tokenClass, new SafeMemoryBuffer(IntPtr.Zero), 0, out returnLength);
369 using (SafeMemoryBuffer infoPtr = new SafeMemoryBuffer((int)returnLength))
370 {
371 if (!NativeMethods.GetTokenInformation(hToken, tokenClass, infoPtr, returnLength, out returnLength))
372 throw new Win32Exception("GetTokenInformation(TokenSource) failed");
373 NativeHelpers.TOKEN_SOURCE source = (NativeHelpers.TOKEN_SOURCE)Marshal.PtrToStructure(
374 infoPtr.DangerousGetHandle(), typeof(NativeHelpers.TOKEN_SOURCE));
375 SourceName = new string(source.SourceName).Replace('\0', ' ').TrimEnd();
376 }
377 }
378
379 private void SetTokenUser(SafeNativeHandle hToken)
380 {
381 NativeHelpers.TokenInformationClass tokenClass = NativeHelpers.TokenInformationClass.TokenUser;
382 UInt32 returnLength;
383 NativeMethods.GetTokenInformation(hToken, tokenClass, new SafeMemoryBuffer(IntPtr.Zero), 0, out returnLength);
384 using (SafeMemoryBuffer infoPtr = new SafeMemoryBuffer((int)returnLength))
385 {
386 if (!NativeMethods.GetTokenInformation(hToken, tokenClass, infoPtr, returnLength, out returnLength))
387 throw new Win32Exception("GetTokenInformation(TokenSource) failed");
388 NativeHelpers.TOKEN_USER user = (NativeHelpers.TOKEN_USER)Marshal.PtrToStructure(
389 infoPtr.DangerousGetHandle(), typeof(NativeHelpers.TOKEN_USER));
390 UserName = LookupSidName(user.User.Sid);
391 UserSid = new SecurityIdentifier(user.User.Sid);
392 }
393 }
394
395 private void SetProfileLoaded()
396 {
397 UInt32 flags;
398 ProfileLoaded = NativeMethods.GetProfileType(out flags);
399 }
400
401 private static string LookupSidName(IntPtr pSid)
402 {
403 StringBuilder name = new StringBuilder(0);
404 StringBuilder domain = new StringBuilder(0);
405 UInt32 nameLength = 0;
406 UInt32 domainLength = 0;
407 UInt32 peUse;
408 NativeMethods.LookupAccountSid(null, pSid, name, ref nameLength, domain, ref domainLength, out peUse);
409 name.EnsureCapacity((int)nameLength);
410 domain.EnsureCapacity((int)domainLength);
411
412 if (!NativeMethods.LookupAccountSid(null, pSid, name, ref nameLength, domain, ref domainLength, out peUse))
413 throw new Win32Exception("LookupAccountSid() failed");
414
415 return String.Format("{0}\\{1}", domain.ToString(), name.ToString());
416 }
417 }
418 }
419 '@
420 $logon = New-Object -TypeName Ansible.Logon
421 ConvertTo-Json -InputObject $logon
422 }.ToString()
423
424 $current_user_raw = [Ansible.Process.ProcessUtil]::CreateProcess($null, "powershell.exe -NoProfile -", $null, $null, $test_whoami + "`r`n")
425 $current_user = ConvertFrom-Json -InputObject $current_user_raw.StandardOut
426
427 $adsi = [ADSI]"WinNT://$env:COMPUTERNAME"
428
429 $standard_user = "become_standard"
430 $admin_user = "become_admin"
431 $become_pass = "password123!$([System.IO.Path]::GetRandomFileName())"
432 $medium_integrity_sid = "S-1-16-8192"
433 $high_integrity_sid = "S-1-16-12288"
434 $system_integrity_sid = "S-1-16-16384"
435
436 $tests = @{
437 "Runas standard user" = {
438 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass,
439 "powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
440 $actual.StandardError | Assert-Equals -Expected ""
441 $actual.ExitCode | Assert-Equals -Expected 0
442
443 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
444 $stdout.LogonType | Assert-Equals -Expected "Interactive"
445 $stdout.ProfileLoaded | Assert-Equals -Expected $true
446 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
447 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
448 }
449
450 "Runas admin user" = {
451 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass,
452 "powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
453 $actual.StandardError | Assert-Equals -Expected ""
454 $actual.ExitCode | Assert-Equals -Expected 0
455 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
456 $stdout.LogonType | Assert-Equals -Expected "Interactive"
457 $stdout.ProfileLoaded | Assert-Equals -Expected $true
458 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
459 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
460 }
461
462 "Runas SYSTEM" = {
463 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null,
464 "powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
465 $actual.StandardError | Assert-Equals -Expected ""
466 $actual.ExitCode | Assert-Equals -Expected 0
467
468 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
469 $stdout.LogonType | Assert-Equals -Expected "System"
470 $stdout.ProfileLoaded | Assert-Equals -Expected $true
471 $stdout.UserSid.Value | Assert-Equals -Expected "S-1-5-18"
472 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $system_integrity_sid
473
474 $with_domain = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NT AUTHORITY\System", $null, "whoami.exe")
475 $with_domain.StandardOut | Assert-Equals -Expected "nt authority\system`r`n"
476 }
477
478 "Runas LocalService" = {
479 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("LocalService", $null,
480 "powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
481 $actual.StandardError | Assert-Equals -Expected ""
482 $actual.ExitCode | Assert-Equals -Expected 0
483
484 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
485 $stdout.LogonType | Assert-Equals -Expected "Service"
486 $stdout.ProfileLoaded | Assert-Equals -Expected $true
487 $stdout.UserSid.Value | Assert-Equals -Expected "S-1-5-19"
488 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $system_integrity_sid
489
490 $with_domain = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NT AUTHORITY\LocalService", $null, "whoami.exe")
491 $with_domain.StandardOut | Assert-Equals -Expected "nt authority\local service`r`n"
492 }
493
494 "Runas NetworkService" = {
495 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NetworkService", $null,
496 "powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
497 $actual.StandardError | Assert-Equals -Expected ""
498 $actual.ExitCode | Assert-Equals -Expected 0
499
500 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
501 $stdout.LogonType | Assert-Equals -Expected "Service"
502 $stdout.ProfileLoaded | Assert-Equals -Expected $true
503 $stdout.UserSid.Value | Assert-Equals -Expected "S-1-5-20"
504 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $system_integrity_sid
505
506 $with_domain = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("NT AUTHORITY\NetworkService", $null, "whoami.exe")
507 $with_domain.StandardOut | Assert-Equals -Expected "nt authority\network service`r`n"
508 }
509
510 "Runas without working dir set" = {
511 $expected = "$env:SystemRoot\system32`r`n"
512 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, 0, "Interactive", $null,
513 'powershell.exe $pwd.Path', $null, $null, "")
514 $actual.StandardOut | Assert-Equals -Expected $expected
515 $actual.StandardError | Assert-Equals -Expected ""
516 $actual.ExitCode | Assert-Equals -Expected 0
517 }
518
519 "Runas with working dir set" = {
520 $expected = "$env:SystemRoot`r`n"
521 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, 0, "Interactive", $null,
522 'powershell.exe $pwd.Path', $env:SystemRoot, $null, "")
523 $actual.StandardOut | Assert-Equals -Expected $expected
524 $actual.StandardError | Assert-Equals -Expected ""
525 $actual.ExitCode | Assert-Equals -Expected 0
526 }
527
528 "Runas without environment set" = {
529 $expected = "Windows_NT`r`n"
530 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, 0, "Interactive", $null,
531 'powershell.exe $env:TEST; $env:OS', $null, $null, "")
532 $actual.StandardOut | Assert-Equals -Expected $expected
533 $actual.StandardError | Assert-Equals -Expected ""
534 $actual.ExitCode | Assert-Equals -Expected 0
535 }
536
537 "Runas with environment set" = {
538 $env_vars = @{
539 TEST = "tesTing"
540 TEST2 = "Testing 2"
541 }
542 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
543 'cmd.exe /c set', $null, $env_vars, "")
544 ("TEST=tesTing" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
545 ("TEST2=Testing 2" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
546 ("OS=Windows_NT" -cnotin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
547 $actual.StandardError | Assert-Equals -Expected ""
548 $actual.ExitCode | Assert-Equals -Expected 0
549 }
550
551 "Runas with string stdin" = {
552 $expected = "input value`r`n`r`n"
553 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
554 'powershell.exe [System.Console]::In.ReadToEnd()', $null, $null, "input value")
555 $actual.StandardOut | Assert-Equals -Expected $expected
556 $actual.StandardError | Assert-Equals -Expected ""
557 $actual.ExitCode | Assert-Equals -Expected 0
558 }
559
560 "Runas with string stdin and newline" = {
561 $expected = "input value`r`n`r`n"
562 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
563 'powershell.exe [System.Console]::In.ReadToEnd()', $null, $null, "input value`r`n")
564 $actual.StandardOut | Assert-Equals -Expected $expected
565 $actual.StandardError | Assert-Equals -Expected ""
566 $actual.ExitCode | Assert-Equals -Expected 0
567 }
568
569 "Runas with byte stdin" = {
570 $expected = "input value`r`n"
571 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0, "Interactive", $null,
572 'powershell.exe [System.Console]::In.ReadToEnd()', $null, $null, [System.Text.Encoding]::UTF8.GetBytes("input value"))
573 $actual.StandardOut | Assert-Equals -Expected $expected
574 $actual.StandardError | Assert-Equals -Expected ""
575 $actual.ExitCode | Assert-Equals -Expected 0
576 }
577
578 "Missing executable" = {
579 $failed = $false
580 try {
581 [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, "fake.exe")
582 } catch {
583 $failed = $true
584 $_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.Process.Win32Exception"
585 $expected = 'Exception calling "CreateProcessAsUser" with "3" argument(s): "CreateProcessWithTokenW() failed '
586 $expected += '(The system cannot find the file specified, Win32ErrorCode 2)"'
587 $_.Exception.Message | Assert-Equals -Expected $expected
588 }
589 $failed | Assert-Equals -Expected $true
590 }
591
592 "CreateProcessAsUser with lpApplicationName" = {
593 $expected = "abc`r`n"
594 $full_path = "$($env:SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe"
595 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $full_path,
596 "Write-Output 'abc'", $null, $null, "")
597 $actual.StandardOut | Assert-Equals -Expected $expected
598 $actual.StandardError | Assert-Equals -Expected ""
599 $actual.ExitCode | Assert-Equals -Expected 0
600
601 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $full_path,
602 "powershell.exe Write-Output 'abc'", $null, $null, "")
603 $actual.StandardOut | Assert-Equals -Expected $expected
604 $actual.StandardError | Assert-Equals -Expected ""
605 $actual.ExitCode | Assert-Equals -Expected 0
606 }
607
608 "CreateProcessAsUser with stderr" = {
609 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $null,
610 "powershell.exe [System.Console]::Error.WriteLine('hi')", $null, $null, "")
611 $actual.StandardOut | Assert-Equals -Expected ""
612 $actual.StandardError | Assert-Equals -Expected "hi`r`n"
613 $actual.ExitCode | Assert-Equals -Expected 0
614 }
615
616 "CreateProcessAsUser with exit code" = {
617 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("SYSTEM", $null, 0, "Interactive", $null,
618 "powershell.exe exit 10", $null, $null, "")
619 $actual.StandardOut | Assert-Equals -Expected ""
620 $actual.StandardError | Assert-Equals -Expected ""
621 $actual.ExitCode | Assert-Equals -Expected 10
622 }
623
624 "Local account with computer name" = {
625 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("$env:COMPUTERNAME\$standard_user", $become_pass,
626 "powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
627 $actual.StandardError | Assert-Equals -Expected ""
628 $actual.ExitCode | Assert-Equals -Expected 0
629
630 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
631 $stdout.LogonType | Assert-Equals -Expected "Interactive"
632 $stdout.ProfileLoaded | Assert-Equals -Expected $true
633 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
634 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
635 }
636
637 "Local account with computer as period" = {
638 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser(".\$standard_user", $become_pass,
639 "powershell.exe -NoProfile -ExecutionPolicy ByPass -File $tmp_script")
640 $actual.StandardError | Assert-Equals -Expected ""
641 $actual.ExitCode | Assert-Equals -Expected 0
642
643 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
644 $stdout.LogonType | Assert-Equals -Expected "Interactive"
645 $stdout.ProfileLoaded | Assert-Equals -Expected $true
646 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
647 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
648 }
649
650 "Local account with invalid password" = {
651 $failed = $false
652 try {
653 [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, "incorrect", "powershell.exe Write-Output abc")
654 } catch {
655 $failed = $true
656 $_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.AccessToken.Win32Exception"
657 # Server 2008 has a slightly different error msg, just assert we get the error 1326
658 ($_.Exception.Message.Contains("Win32ErrorCode 1326")) | Assert-Equals -Expected $true
659 }
660 $failed | Assert-Equals -Expected $true
661 }
662
663 "Invalid account" = {
664 $failed = $false
665 try {
666 [Ansible.Become.BecomeUtil]::CreateProcessAsUser("incorrect", "incorrect", "powershell.exe Write-Output abc")
667 } catch {
668 $failed = $true
669 $_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "System.Security.Principal.IdentityNotMappedException"
670 $expected = 'Exception calling "CreateProcessAsUser" with "3" argument(s): "Some or all '
671 $expected += 'identity references could not be translated."'
672 $_.Exception.Message | Assert-Equals -Expected $expected
673 }
674 $failed | Assert-Equals -Expected $true
675 }
676
677 "Interactive logon with standard" = {
678 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
679 "Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
680 $actual.StandardError | Assert-Equals -Expected ""
681 $actual.ExitCode | Assert-Equals -Expected 0
682
683 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
684 $stdout.LogonType | Assert-Equals -Expected "Interactive"
685 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
686 $stdout.ProfileLoaded | Assert-Equals -Expected $true
687 $stdout.SourceName | Assert-Equals -Expected "Advapi"
688 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
689 }
690
691 "Batch logon with standard" = {
692 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
693 "Batch", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
694 $actual.StandardError | Assert-Equals -Expected ""
695 $actual.ExitCode | Assert-Equals -Expected 0
696
697 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
698 $stdout.LogonType | Assert-Equals -Expected "Batch"
699 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
700 $stdout.ProfileLoaded | Assert-Equals -Expected $true
701 $stdout.SourceName | Assert-Equals -Expected "Advapi"
702 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
703 }
704
705 "Network logon with standard" = {
706 # Server 2008 will not work with become to Network or Network Credentials
707 if ([System.Environment]::OSVersion.Version -lt [Version]"6.1") {
708 continue
709 }
710 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
711 "Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
712 $actual.StandardError | Assert-Equals -Expected ""
713 $actual.ExitCode | Assert-Equals -Expected 0
714
715 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
716 $stdout.LogonType | Assert-Equals -Expected "Network"
717 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
718 $stdout.ProfileLoaded | Assert-Equals -Expected $true
719 $stdout.SourceName | Assert-Equals -Expected "Advapi"
720 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
721 }
722
723 "Network with cleartext logon with standard" = {
724 # Server 2008 will not work with become to Network or Network Cleartext
725 if ([System.Environment]::OSVersion.Version -lt [Version]"6.1") {
726 continue
727 }
728 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, $become_pass, "WithProfile",
729 "NetworkCleartext", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
730 $actual.StandardError | Assert-Equals -Expected ""
731 $actual.ExitCode | Assert-Equals -Expected 0
732
733 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
734 $stdout.LogonType | Assert-Equals -Expected "NetworkCleartext"
735 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
736 $stdout.ProfileLoaded | Assert-Equals -Expected $true
737 $stdout.SourceName | Assert-Equals -Expected "Advapi"
738 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
739 }
740
741 "Logon without password with standard" = {
742 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, [NullString]::Value, "WithProfile",
743 "Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
744 $actual.StandardError | Assert-Equals -Expected ""
745 $actual.ExitCode | Assert-Equals -Expected 0
746
747 # Too unstable, there might be another process still lingering which causes become to steal instead of using
748 # S4U. Just don't check the type and source to verify we can become without a password
749 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
750 # $stdout.LogonType | Assert-Equals -Expected "Batch"
751 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
752 $stdout.ProfileLoaded | Assert-Equals -Expected $true
753 # $stdout.SourceName | Assert-Equals -Expected "ansible"
754 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
755 }
756
757 "Logon without password and network type with standard" = {
758 # Server 2008 will not work with become to Network or Network Cleartext
759 if ([System.Environment]::OSVersion.Version -lt [Version]"6.1") {
760 continue
761 }
762 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($standard_user, [NullString]::Value, "WithProfile",
763 "Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
764 $actual.StandardError | Assert-Equals -Expected ""
765 $actual.ExitCode | Assert-Equals -Expected 0
766
767 # Too unstable, there might be another process still lingering which causes become to steal instead of using
768 # S4U. Just don't check the type and source to verify we can become without a password
769 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
770 # $stdout.LogonType | Assert-Equals -Expected "Network"
771 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $medium_integrity_sid
772 $stdout.ProfileLoaded | Assert-Equals -Expected $true
773 # $stdout.SourceName | Assert-Equals -Expected "ansible"
774 $stdout.UserSid.Value | Assert-Equals -Expected $standard_user_sid
775 }
776
777 "Interactive logon with admin" = {
778 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
779 "Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
780 $actual.StandardError | Assert-Equals -Expected ""
781 $actual.ExitCode | Assert-Equals -Expected 0
782
783 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
784 $stdout.LogonType | Assert-Equals -Expected "Interactive"
785 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
786 $stdout.ProfileLoaded | Assert-Equals -Expected $true
787 $stdout.SourceName | Assert-Equals -Expected "Advapi"
788 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
789 }
790
791 "Batch logon with admin" = {
792 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
793 "Batch", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
794 $actual.StandardError | Assert-Equals -Expected ""
795 $actual.ExitCode | Assert-Equals -Expected 0
796
797 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
798 $stdout.LogonType | Assert-Equals -Expected "Batch"
799 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
800 $stdout.ProfileLoaded | Assert-Equals -Expected $true
801 $stdout.SourceName | Assert-Equals -Expected "Advapi"
802 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
803 }
804
805 "Network logon with admin" = {
806 # Server 2008 will not work with become to Network or Network Credentials
807 if ([System.Environment]::OSVersion.Version -lt [Version]"6.1") {
808 continue
809 }
810 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
811 "Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
812 $actual.StandardError | Assert-Equals -Expected ""
813 $actual.ExitCode | Assert-Equals -Expected 0
814
815 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
816 $stdout.LogonType | Assert-Equals -Expected "Network"
817 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
818 $stdout.ProfileLoaded | Assert-Equals -Expected $true
819 $stdout.SourceName | Assert-Equals -Expected "Advapi"
820 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
821 }
822
823 "Network with cleartext logon with admin" = {
824 # Server 2008 will not work with become to Network or Network Credentials
825 if ([System.Environment]::OSVersion.Version -lt [Version]"6.1") {
826 continue
827 }
828 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, "WithProfile",
829 "NetworkCleartext", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
830 $actual.StandardError | Assert-Equals -Expected ""
831 $actual.ExitCode | Assert-Equals -Expected 0
832
833 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
834 $stdout.LogonType | Assert-Equals -Expected "NetworkCleartext"
835 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
836 $stdout.ProfileLoaded | Assert-Equals -Expected $true
837 $stdout.SourceName | Assert-Equals -Expected "Advapi"
838 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
839 }
840
841 "Fail to logon with null or empty password" = {
842 $failed = $false
843 try {
844 # Having $null or an empty string means we are trying to become a user with a blank password and not
845 # become without setting the password. This is confusing as $null gets converted to "" and we need to
846 # use [NullString]::Value instead if we want that behaviour. This just tests to see that an empty
847 # string won't go the S4U route.
848 [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $null, "WithProfile",
849 "Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
850 } catch {
851 $failed = $true
852 $_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.AccessToken.Win32Exception"
853 # Server 2008 has a slightly different error msg, just assert we get the error 1326
854 ($_.Exception.Message.Contains("Win32ErrorCode 1326")) | Assert-Equals -Expected $true
855 }
856 $failed | Assert-Equals -Expected $true
857 }
858
859 "Logon without password with admin" = {
860 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, [NullString]::Value, "WithProfile",
861 "Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
862 $actual.StandardError | Assert-Equals -Expected ""
863 $actual.ExitCode | Assert-Equals -Expected 0
864
865 # Too unstable, there might be another process still lingering which causes become to steal instead of using
866 # S4U. Just don't check the type and source to verify we can become without a password
867 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
868 # $stdout.LogonType | Assert-Equals -Expected "Batch"
869 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
870 $stdout.ProfileLoaded | Assert-Equals -Expected $true
871 # $stdout.SourceName | Assert-Equals -Expected "ansible"
872 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
873 }
874
875 "Logon without password and network type with admin" = {
876 # become network doesn't work on Server 2008
877 if ([System.Environment]::OSVersion.Version -lt [Version]"6.1") {
878 continue
879 }
880 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, [NullString]::Value, "WithProfile",
881 "Network", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
882 $actual.StandardError | Assert-Equals -Expected ""
883 $actual.ExitCode | Assert-Equals -Expected 0
884
885 # Too unstable, there might be another process still lingering which causes become to steal instead of using
886 # S4U. Just don't check the type and source to verify we can become without a password
887 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
888 # $stdout.LogonType | Assert-Equals -Expected "Network"
889 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
890 $stdout.ProfileLoaded | Assert-Equals -Expected $true
891 # $stdout.SourceName | Assert-Equals -Expected "ansible"
892 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
893 }
894
895 "Logon without profile with admin" = {
896 # Server 2008 and 2008 R2 does not support running without the profile being set
897 if ([System.Environment]::OSVersion.Version -lt [Version]"6.2") {
898 continue
899 }
900
901 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser($admin_user, $become_pass, 0,
902 "Interactive", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
903 $actual.StandardError | Assert-Equals -Expected ""
904 $actual.ExitCode | Assert-Equals -Expected 0
905
906 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
907 $stdout.LogonType | Assert-Equals -Expected "Interactive"
908 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $high_integrity_sid
909 $stdout.ProfileLoaded | Assert-Equals -Expected $false
910 $stdout.SourceName | Assert-Equals -Expected "Advapi"
911 $stdout.UserSid.Value | Assert-Equals -Expected $admin_user_sid
912 }
913
914 "Logon with network credentials and no profile" = {
915 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("fakeuser", "fakepassword", "NetcredentialsOnly",
916 "NewCredentials", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
917 $actual.StandardError | Assert-Equals -Expected ""
918 $actual.ExitCode | Assert-Equals -Expected 0
919
920 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
921 $stdout.LogonType | Assert-Equals -Expected "NewCredentials"
922 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $current_user.MandatoryLabelSid.Value
923
924 # while we didn't set WithProfile, the new process is based on the current process
925 $stdout.ProfileLoaded | Assert-Equals -Expected $current_user.ProfileLoaded
926 $stdout.SourceName | Assert-Equals -Expected "Advapi"
927 $stdout.UserSid.Value | Assert-Equals -Expected $current_user.UserSid.Value
928 }
929
930 "Logon with network credentials and with profile" = {
931 $actual = [Ansible.Become.BecomeUtil]::CreateProcessAsUser("fakeuser", "fakepassword", "NetcredentialsOnly, WithProfile",
932 "NewCredentials", $null, "powershell.exe -NoProfile -", $tmp_dir, $null, $test_whoami + "`r`n")
933 $actual.StandardError | Assert-Equals -Expected ""
934 $actual.ExitCode | Assert-Equals -Expected 0
935
936 $stdout = ConvertFrom-Json -InputObject $actual.StandardOut
937 $stdout.LogonType | Assert-Equals -Expected "NewCredentials"
938 $stdout.MandatoryLabelSid.Value | Assert-Equals -Expected $current_user.MandatoryLabelSid.Value
939 $stdout.ProfileLoaded | Assert-Equals -Expected $current_user.ProfileLoaded
940 $stdout.SourceName | Assert-Equals -Expected "Advapi"
941 $stdout.UserSid.Value | Assert-Equals -Expected $current_user.UserSid.Value
942 }
943 }
944
945 try {
946 $tmp_dir = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName())
947 New-Item -Path $tmp_dir -ItemType Directory > $null
948 $acl = Get-Acl -Path $tmp_dir
949 $ace = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList @(
950 New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList ([System.Security.Principal.WellKnownSidType]::WorldSid, $null)
951 [System.Security.AccessControl.FileSystemRights]::FullControl,
952 [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit",
953 [System.Security.AccessControl.PropagationFlags]::None,
954 [System.Security.AccessControl.AccessControlType]::Allow
955 )
956 $acl.AddAccessRule($ace)
957 Set-Acl -Path $tmp_dir -AclObject $acl
958
959 $tmp_script = Join-Path -Path $tmp_dir -ChildPath "whoami.ps1"
960 Set-Content -LiteralPath $tmp_script -Value $test_whoami
961
962 foreach ($user in $standard_user, $admin_user) {
963 $user_obj = $adsi.Children | Where-Object { $_.SchemaClassName -eq "User" -and $_.Name -eq $user }
964 if ($null -eq $user_obj) {
965 $user_obj = $adsi.Create("User", $user)
966 $user_obj.SetPassword($become_pass)
967 $user_obj.SetInfo()
968 } else {
969 $user_obj.SetPassword($become_pass)
970 }
971 $user_obj.RefreshCache()
972
973 if ($user -eq $standard_user) {
974 $standard_user_sid = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @($user_obj.ObjectSid.Value, 0)).Value
975 $group = [System.Security.Principal.WellKnownSidType]::BuiltinUsersSid
976 } else {
977 $admin_user_sid = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @($user_obj.ObjectSid.Value, 0)).Value
978 $group = [System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid
979 }
980 $group = (New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $group, $null).Value
981 [string[]]$current_groups = $user_obj.Groups() | ForEach-Object {
982 New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @($_.GetType().InvokeMember("objectSID", "GetProperty", $null, $_, $null), 0)
983 }
984 if ($current_groups -notcontains $group) {
985 $group_obj = $adsi.Children | Where-Object {
986 if ($_.SchemaClassName -eq "Group") {
987 $group_sid = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList @($_.objectSID.Value, 0)
988 $group_sid -eq $group
989 }
990 }
991 $group_obj.Add($user_obj.Path)
992 }
993 }
994 foreach ($test_impl in $tests.GetEnumerator()) {
995 $test = $test_impl.Key
996 &$test_impl.Value
997 }
998 } finally {
999 Remove-Item -LiteralPath $tmp_dir -Force -Recurse
1000 foreach ($user in $standard_user, $admin_user) {
1001 $user_obj = $adsi.Children | Where-Object { $_.SchemaClassName -eq "User" -and $_.Name -eq $user }
1002 $adsi.Delete("User", $user_obj.Name.Value)
1003 }
1004 }
1005
1006
1007 $module.Result.data = "success"
1008 $module.ExitJson()
1009
1010