@ -171,9 +171,12 @@ Set-StrictMode -Version 2
$ ErrorActionPreference = " Stop "
$ ErrorActionPreference = " Stop "
$ helper_def = @ "
$ helper_def = @ "
using Microsoft . Win32 . SafeHandles ;
using System ;
using System ;
using System . Collections . Generic ;
using System . Collections . Generic ;
using System . Diagnostics ;
using System . IO ;
using System . IO ;
using System . Linq ;
using System . Runtime . InteropServices ;
using System . Runtime . InteropServices ;
using System . Security . AccessControl ;
using System . Security . AccessControl ;
using System . Security . Principal ;
using System . Security . Principal ;
@ -212,9 +215,9 @@ namespace Ansible
public Int16 wShowWindow ;
public Int16 wShowWindow ;
public Int16 cbReserved2 ;
public Int16 cbReserved2 ;
public IntPtr lpReserved2 ;
public IntPtr lpReserved2 ;
public IntPtr hStdInput ;
public SafeFileHandle hStdInput ;
public IntPtr hStdOutput ;
public SafeFileHandle hStdOutput ;
public IntPtr hStdError ;
public SafeFileHandle hStdError ;
public STARTUPINFO ( )
public STARTUPINFO ( )
{
{
cb = Marshal . SizeOf ( this ) ;
cb = Marshal . SizeOf ( this ) ;
@ -254,6 +257,42 @@ namespace Ansible
public SID_AND_ATTRIBUTES User ;
public SID_AND_ATTRIBUTES User ;
}
}
[ StructLayout ( LayoutKind . Sequential ) ]
public struct IO_COUNTERS
{
public UInt64 ReadOperationCount ;
public UInt64 WriteOperationCount ;
public UInt64 OtherOperationCount ;
public UInt64 ReadTransferCount ;
public UInt64 WriteTransferCount ;
public UInt64 OtherTransferCount ;
}
[ StructLayout ( LayoutKind . Sequential ) ]
public struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public UInt64 PerProcessUserTimeLimit ;
public UInt64 PerJobUserTimeLimit ;
public LimitFlags LimitFlags ;
public UIntPtr MinimumWorkingSetSize ;
public UIntPtr MaximumWorkingSetSize ;
public UInt32 ActiveProcessLimit ;
public UIntPtr Affinity ;
public UInt32 PriorityClass ;
public UInt32 SchedulingClass ;
}
[ StructLayout ( LayoutKind . Sequential ) ]
public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation ;
public IO_COUNTERS IoInfo ;
public UIntPtr ProcessMemoryLimit ;
public UIntPtr JobMemoryLimit ;
public UIntPtr PeakProcessMemoryUsed ;
public UIntPtr PeakJobMemoryUsed ;
}
[ Flags ]
[ Flags ]
public enum StartupInfoFlags : uint
public enum StartupInfoFlags : uint
{
{
@ -263,6 +302,7 @@ namespace Ansible
[ Flags ]
[ Flags ]
public enum CreationFlags : uint
public enum CreationFlags : uint
{
{
CREATE_BREAKAWAY_FROM_JOB = 0x01000000 ,
CREATE_DEFAULT_ERROR_MODE = 0x04000000 ,
CREATE_DEFAULT_ERROR_MODE = 0x04000000 ,
CREATE_NEW_CONSOLE = 0x00000010 ,
CREATE_NEW_CONSOLE = 0x00000010 ,
CREATE_NEW_PROCESS_GROUP = 0x00000200 ,
CREATE_NEW_PROCESS_GROUP = 0x00000200 ,
@ -353,11 +393,35 @@ namespace Ansible
TokenImpersonation
TokenImpersonation
}
}
enum JobObjectInfoType
{
AssociateCompletionPortInformation = 7 ,
BasicLimitInformation = 2 ,
BasicUIRestrictions = 4 ,
EndOfJobTimeInformation = 6 ,
ExtendedLimitInformation = 9 ,
SecurityLimitInformation = 5 ,
GroupInformation = 11
}
[ Flags ]
enum ThreadAccessRights : uint
{
SUSPEND_RESUME = 0x0002
}
[ Flags ]
public enum LimitFlags : uint
{
JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800 ,
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000
}
class NativeWaitHandle : WaitHandle
class NativeWaitHandle : WaitHandle
{
{
public NativeWaitHandle ( IntPtr handle )
public NativeWaitHandle ( IntPtr handle )
{
{
this . Handle = handle ;
this . SafeWait Handle = new SafeWaitHandle ( handle, false ) ;
}
}
}
}
@ -380,6 +444,69 @@ namespace Ansible
public uint ExitCode { get ; internal set ; }
public uint ExitCode { get ; internal set ; }
}
}
public class Job : IDisposable
{
[ DllImport ( " kernel32.dll " , SetLastError = true , CharSet = CharSet . Unicode ) ]
private static extern IntPtr CreateJobObject (
IntPtr lpJobAttributes ,
string lpName ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
private static extern bool SetInformationJobObject (
IntPtr hJob ,
JobObjectInfoType JobObjectInfoClass ,
IntPtr lpJobObjectInfo ,
UInt32 cbJobObjectInfoLength ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
private static extern bool AssignProcessToJobObject (
IntPtr hJob ,
IntPtr hProcess ) ;
[ DllImport ( " kernel32.dll " ) ]
private static extern bool CloseHandle (
IntPtr hObject ) ;
private IntPtr handle ;
public Job ( )
{
handle = CreateJobObject ( IntPtr . Zero , null ) ;
if ( handle == IntPtr . Zero )
throw new Win32Exception ( " CreateJobObject() failed " ) ;
JOBOBJECT_BASIC_LIMIT_INFORMATION jobInfo = new JOBOBJECT_BASIC_LIMIT_INFORMATION ( ) ;
jobInfo . LimitFlags = LimitFlags . JOB_OBJECT_LIMIT_BREAKAWAY_OK | LimitFlags . JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE ;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedJobInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION ( ) ;
extendedJobInfo . BasicLimitInformation = jobInfo ;
int length = Marshal . SizeOf ( typeof ( JOBOBJECT_EXTENDED_LIMIT_INFORMATION ) ) ;
IntPtr pExtendedJobInfo = Marshal . AllocHGlobal ( length ) ;
Marshal . StructureToPtr ( extendedJobInfo , pExtendedJobInfo , false ) ;
if ( ! SetInformationJobObject ( handle , JobObjectInfoType . ExtendedLimitInformation , pExtendedJobInfo , ( UInt32 ) length ) )
throw new Win32Exception ( " SetInformationJobObject() failed " ) ;
}
public void AssignProcess ( IntPtr processHandle )
{
if ( ! AssignProcessToJobObject ( handle , processHandle ) )
throw new Win32Exception ( " AssignProcessToJobObject() failed " ) ;
}
public void Dispose ( )
{
if ( handle != IntPtr . Zero )
{
CloseHandle ( handle ) ;
handle = IntPtr . Zero ;
}
GC . SuppressFinalize ( this ) ;
}
}
public class BecomeUtil
public class BecomeUtil
{
{
[ DllImport ( " advapi32.dll " , SetLastError = true ) ]
[ DllImport ( " advapi32.dll " , SetLastError = true ) ]
@ -407,14 +534,14 @@ namespace Ansible
[ DllImport ( " kernel32.dll " ) ]
[ DllImport ( " kernel32.dll " ) ]
private static extern bool CreatePipe (
private static extern bool CreatePipe (
out IntPtr hReadPipe ,
out SafeFileHandle hReadPipe ,
out IntPtr hWritePipe ,
out SafeFileHandle hWritePipe ,
SECURITY_ATTRIBUTES lpPipeAttributes ,
SECURITY_ATTRIBUTES lpPipeAttributes ,
uint nSize ) ;
uint nSize ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
private static extern bool SetHandleInformation (
private static extern bool SetHandleInformation (
IntPtr hObject ,
SafeFileHandle hObject ,
HandleFlags dwMask ,
HandleFlags dwMask ,
int dwFlags ) ;
int dwFlags ) ;
@ -431,7 +558,8 @@ namespace Ansible
private static extern IntPtr GetProcessWindowStation ( ) ;
private static extern IntPtr GetProcessWindowStation ( ) ;
[ DllImport ( " user32.dll " , SetLastError = true ) ]
[ DllImport ( " user32.dll " , SetLastError = true ) ]
private static extern IntPtr GetThreadDesktop ( int dwThreadId ) ;
private static extern IntPtr GetThreadDesktop (
int dwThreadId ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
private static extern int GetCurrentThreadId ( ) ;
private static extern int GetCurrentThreadId ( ) ;
@ -480,17 +608,27 @@ namespace Ansible
out IntPtr phNewToken ) ;
out IntPtr phNewToken ) ;
[ DllImport ( " advapi32.dll " , SetLastError = true ) ]
[ DllImport ( " advapi32.dll " , SetLastError = true ) ]
p ublic static extern bool ImpersonateLoggedOnUser (
p rivate static extern bool ImpersonateLoggedOnUser (
IntPtr hToken ) ;
IntPtr hToken ) ;
[ DllImport ( " advapi32.dll " , SetLastError = true ) ]
[ DllImport ( " advapi32.dll " , SetLastError = true ) ]
public static extern bool RevertToSelf ( ) ;
private static extern bool RevertToSelf ( ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
private static extern SafeFileHandle OpenThread (
ThreadAccessRights dwDesiredAccess ,
bool bInheritHandle ,
int dwThreadId ) ;
[ DllImport ( " kernel32.dll " , SetLastError = true ) ]
private static extern int ResumeThread (
SafeHandle hThread ) ;
public static CommandResult RunAsUser ( string username , string password , string lpCommandLine , string lpCurrentDirectory , string stdinInput )
public static CommandResult RunAsUser ( string username , string password , string lpCommandLine , string lpCurrentDirectory , string stdinInput )
{
{
SecurityIdentifier account = GetBecomeSid ( username ) ;
SecurityIdentifier account = GetBecomeSid ( username ) ;
CreationFlags startup_flags = CreationFlags . CREATE_UNICODE_ENVIRONMENT ;
CreationFlags startup_flags = CreationFlags . CREATE_UNICODE_ENVIRONMENT | CreationFlags . CREATE_BREAKAWAY_FROM_JOB | CreationFlags . CREATE_SUSPENDED ;
STARTUPINFOEX si = new STARTUPINFOEX ( ) ;
STARTUPINFOEX si = new STARTUPINFOEX ( ) ;
si . startupInfo . dwFlags = ( int ) StartupInfoFlags . USESTDHANDLES ;
si . startupInfo . dwFlags = ( int ) StartupInfoFlags . USESTDHANDLES ;
@ -499,7 +637,7 @@ namespace Ansible
pipesec . bInheritHandle = true ;
pipesec . bInheritHandle = true ;
/ / Create the stdout , stderr and stdin pipes used in the process and add to the startupInfo
/ / Create the stdout , stderr and stdin pipes used in the process and add to the startupInfo
IntPtr stdout_read , stdout_write , stderr_read , stderr_write , stdin_read , stdin_write = IntPtr . Zero ;
SafeFileHandle stdout_read , stdout_write , stderr_read , stderr_write , stdin_read , stdin_write ;
if ( ! CreatePipe ( out stdout_read , out stdout_write , pipesec , 0 ) )
if ( ! CreatePipe ( out stdout_read , out stdout_write , pipesec , 0 ) )
throw new Win32Exception ( " STDOUT pipe setup failed " ) ;
throw new Win32Exception ( " STDOUT pipe setup failed " ) ;
if ( ! SetHandleInformation ( stdout_read , HandleFlags . INHERIT , 0 ) )
if ( ! SetHandleInformation ( stdout_read , HandleFlags . INHERIT , 0 ) )
@ -521,7 +659,7 @@ namespace Ansible
/ / Setup the stdin buffer
/ / Setup the stdin buffer
UTF8Encoding utf8_encoding = new UTF8Encoding ( false ) ;
UTF8Encoding utf8_encoding = new UTF8Encoding ( false ) ;
FileStream stdin_fs = new FileStream ( stdin_write , FileAccess . Write , true , 32768 ) ;
FileStream stdin_fs = new FileStream ( stdin_write , FileAccess . Write , 32768 ) ;
StreamWriter stdin = new StreamWriter ( stdin_fs , utf8_encoding , 32768 ) ;
StreamWriter stdin = new StreamWriter ( stdin_fs , utf8_encoding , 32768 ) ;
/ / Create the environment block if set
/ / Create the environment block if set
@ -554,26 +692,44 @@ namespace Ansible
if ( ! launch_success )
if ( ! launch_success )
throw new Win32Exception ( " Failed to start become process " ) ;
throw new Win32Exception ( " Failed to start become process " ) ;
/ / If 2012 / 8 + OS , create new job with JOB_OBJECT_LIMIT_BREAKAWAY_OK
/ / so that async can work
Job job = null ;
if ( Environment . OSVersion . Version > = new Version ( " 6.2 " ) )
{
job = new Job ( ) ;
job . AssignProcess ( pi . hProcess ) ;
}
ResumeProcessById ( pi . dwProcessId ) ;
CommandResult result = new CommandResult ( ) ;
try
{
/ / Setup the output buffers and get stdout / stderr
/ / Setup the output buffers and get stdout / stderr
FileStream stdout_fs = new FileStream ( stdout_read , FileAccess . Read , true , 4096 ) ;
FileStream stdout_fs = new FileStream ( stdout_read , FileAccess . Read , 4096 ) ;
StreamReader stdout = new StreamReader ( stdout_fs , utf8_encoding , true , 4096 ) ;
StreamReader stdout = new StreamReader ( stdout_fs , utf8_encoding , true , 4096 ) ;
CloseHandle ( stdout_write ) ;
stdout_write . Close ( ) ;
FileStream stderr_fs = new FileStream ( stderr_read , FileAccess . Read , true , 4096 ) ;
FileStream stderr_fs = new FileStream ( stderr_read , FileAccess . Read , 4096 ) ;
StreamReader stderr = new StreamReader ( stderr_fs , utf8_encoding , true , 4096 ) ;
StreamReader stderr = new StreamReader ( stderr_fs , utf8_encoding , true , 4096 ) ;
CloseHandle ( stderr_write ) ;
stderr_write . Close ( ) ;
stdin . WriteLine ( stdinInput ) ;
stdin . WriteLine ( stdinInput ) ;
stdin . Close ( ) ;
stdin . Close ( ) ;
string stdout_str , stderr_str = null ;
string stdout_str , stderr_str = null ;
GetProcessOutput ( stdout , stderr , out stdout_str , out stderr_str ) ;
GetProcessOutput ( stdout , stderr , out stdout_str , out stderr_str ) ;
uint rc = GetProcessExitCode ( pi . hProcess ) ;
UInt32 rc = GetProcessExitCode ( pi . hProcess ) ;
CommandResult result = new CommandResult ( ) ;
result . StandardOut = stdout_str ;
result . StandardOut = stdout_str ;
result . StandardError = stderr_str ;
result . StandardError = stderr_str ;
result . ExitCode = rc ;
result . ExitCode = rc ;
}
finally
{
if ( job != null )
job . Dispose ( ) ;
}
return result ;
return result ;
}
}
@ -604,71 +760,64 @@ namespace Ansible
GrantAccessToWindowStationAndDesktop ( account ) ;
GrantAccessToWindowStationAndDesktop ( account ) ;
string account_sid = account . ToString ( ) ;
string account_sid = account . ToString ( ) ;
bool impersonated = false ;
IntPtr hSystemTokenDup = IntPtr . Zero ;
if ( service_sids . Contains ( account_sid ) )
/ / Try to get SYSTEM token handle so we can impersonate to get full admin token
IntPtr hSystemToken = GetSystemUserHandle ( ) ;
if ( hSystemToken == IntPtr . Zero & & service_sids . Contains ( account_sid ) )
{
{
/ / We are trying to become to a service account
/ / We need the SYSTEM token if we want to become one of those accounts , fail here
IntPtr hToken = GetUserHandle ( ) ;
throw new Win32Exception ( " Failed to get token for NT AUTHORITY \\ SYSTEM " ) ;
if ( hToken == IntPtr . Zero )
}
throw new Exception ( " Failed to get token for NT AUTHORITY \\ SYSTEM " ) ;
else if ( hSystemToken != IntPtr . Zero )
IntPtr hTokenDup = IntPtr . Zero ;
try
{
{
if ( ! DuplicateTokenEx (
/ / We have the token , need to duplicate and impersonate
hToken ,
bool dupResult = DuplicateTokenEx (
hSystemToken ,
TokenAccessLevels . MaximumAllowed ,
TokenAccessLevels . MaximumAllowed ,
IntPtr . Zero ,
IntPtr . Zero ,
SECURITY_IMPERSONATION_LEVEL . SecurityImpersonation ,
SECURITY_IMPERSONATION_LEVEL . SecurityImpersonation ,
TOKEN_TYPE . TokenPrimary ,
TOKEN_TYPE . TokenPrimary ,
out hTokenDup ) )
out hSystemTokenDup ) ;
int lastError = Marshal . GetLastWin32Error ( ) ;
CloseHandle ( hSystemToken ) ;
if ( ! dupResult & & service_sids . Contains ( account_sid ) )
throw new Win32Exception ( lastError , " Failed to duplicate token for NT AUTHORITY \\ SYSTEM " ) ;
else if ( dupResult & & account_sid != " S-1-5-18 " )
{
{
throw new Win32Exception ( " Failed to duplicate the SYSTEM account token " ) ;
if ( ImpersonateLoggedOnUser ( hSystemTokenDup ) )
impersonated = true ;
else if ( service_sids . Contains ( account_sid ) )
throw new Win32Exception ( " Failed to impersonate as SYSTEM account " ) ;
}
}
}
}
finally
{
CloseHandle ( hToken ) ;
}
string lpszDomain = " NT AUTHORITY " ;
LogonType logonType ;
string lpszUsername = null ;
string domain = null ;
if ( service_sids . Contains ( account_sid ) )
{
logonType = LogonType . LOGON32_LOGON_SERVICE ;
domain = " NT AUTHORITY " ;
password = null ;
switch ( account_sid )
switch ( account_sid )
{
{
case " S-1-5-18 " :
case " S-1-5-18 " :
tokens . Add ( hTokenDup ) ;
tokens . Add ( h System TokenDup) ;
return tokens ;
return tokens ;
case " S-1-5-19 " :
case " S-1-5-19 " :
lpszU sername = " LocalService " ;
u sername = " LocalService " ;
break ;
break ;
case " S-1-5-20 " :
case " S-1-5-20 " :
lpszU sername = " NetworkService " ;
u sername = " NetworkService " ;
break ;
break ;
}
}
if ( ! ImpersonateLoggedOnUser ( hTokenDup ) )
throw new Win32Exception ( " Failed to impersonate as SYSTEM account " ) ;
IntPtr newToken = IntPtr . Zero ;
if ( ! LogonUser (
lpszUsername ,
lpszDomain ,
null ,
LogonType . LOGON32_LOGON_SERVICE ,
LogonProvider . LOGON32_PROVIDER_DEFAULT ,
out newToken ) )
{
throw new Win32Exception ( " LogonUser failed " ) ;
}
RevertToSelf ( ) ;
tokens . Add ( newToken ) ;
return tokens ;
}
}
else
else
{
{
/ / We are trying to become a local or domain account
/ / We are trying to become a local or domain account
string domain = null ;
logonType = LogonType . LOGON32_LOGON_INTERACTIVE ;
if ( username . Contains ( @ " \" ))
if ( username . Contains ( @ " \" ))
{
{
var user_split = username . Split ( Convert . ToChar ( @ " \" ));
var user_split = username . Split ( Convert . ToChar ( @ " \" ));
@ -679,31 +828,35 @@ namespace Ansible
domain = null ;
domain = null ;
else
else
domain = " . " ;
domain = " . " ;
}
/ / Logon and get the token
IntPtr hToken = IntPtr . Zero ;
IntPtr hToken = IntPtr . Zero ;
if ( ! LogonUser (
if ( ! LogonUser (
username ,
username ,
domain ,
domain ,
password ,
password ,
LogonType . LOGON32_LOGON_INTERACTIVE ,
logonType ,
LogonProvider . LOGON32_PROVIDER_DEFAULT ,
LogonProvider . LOGON32_PROVIDER_DEFAULT ,
out hToken ) )
out hToken ) )
{
{
throw new Win32Exception ( " LogonUser failed " ) ;
throw new Win32Exception ( " LogonUser failed " ) ;
}
}
/ / Get the elevate token
if ( ! service_sids . Contains ( account_sid ) )
{
/ / Try and get the elevated token for local / domain account
IntPtr hTokenElevated = GetElevatedToken ( hToken ) ;
IntPtr hTokenElevated = GetElevatedToken ( hToken ) ;
tokens . Add ( hTokenElevated ) ;
tokens . Add ( hTokenElevated ) ;
}
tokens . Add ( hToken ) ;
tokens . Add ( hToken ) ;
if ( impersonated )
RevertToSelf ( ) ;
return tokens ;
return tokens ;
}
}
}
private static IntPtr Get UserHandle( )
private static IntPtr Get System UserHandle( )
{
{
uint array_byte_size = 1024 * sizeof ( uint ) ;
uint array_byte_size = 1024 * sizeof ( uint ) ;
IntPtr [ ] pids = new IntPtr [ 1024 ] ;
IntPtr [ ] pids = new IntPtr [ 1024 ] ;
@ -864,6 +1017,44 @@ namespace Ansible
security . Persist ( safeHandle , AccessControlSections . Access ) ;
security . Persist ( safeHandle , AccessControlSections . Access ) ;
}
}
private static void ResumeThreadById ( int threadId )
{
var threadHandle = OpenThread ( ThreadAccessRights . SUSPEND_RESUME , false , threadId ) ;
if ( threadHandle . IsInvalid )
throw new Win32Exception ( String . Format ( " Thread ID {0} is invalid " , threadId ) ) ;
try
{
if ( ResumeThread ( threadHandle ) == - 1 )
throw new Win32Exception ( String . Format ( " Thread ID {0} cannot be resumed " , threadId ) ) ;
}
finally
{
threadHandle . Dispose ( ) ;
}
}
private static void ResumeProcessById ( int pid )
{
var proc = Process . GetProcessById ( pid ) ;
/ / wait for at least one suspended thread in the process ( this handles possible slow startup race where
/ / primary thread of created - suspended process has not yet become runnable )
var retryCount = 0 ;
while ( ! proc . Threads . OfType < ProcessThread > ( ) . Any ( t = > t . ThreadState == System . Diagnostics . ThreadState . Wait & &
t . WaitReason == ThreadWaitReason . Suspended ) )
{
proc . Refresh ( ) ;
Thread . Sleep ( 50 ) ;
if ( retryCount > 100 )
throw new InvalidOperationException ( String . Format ( " No threads were suspended in target PID {0} after 5s " , pid ) ) ;
}
foreach ( var thread in proc . Threads . OfType < ProcessThread > ( ) . Where ( t = > t . ThreadState == System . Diagnostics . ThreadState . Wait & &
t . WaitReason == ThreadWaitReason . Suspended ) )
ResumeThreadById ( thread . Id ) ;
}
private class GenericSecurity : NativeObjectSecurity
private class GenericSecurity : NativeObjectSecurity
{
{
public GenericSecurity ( bool isContainer , ResourceType resType , SafeHandle objectHandle , AccessControlSections sectionsRequested )
public GenericSecurity ( bool isContainer , ResourceType resType , SafeHandle objectHandle , AccessControlSections sectionsRequested )
@ -969,8 +1160,7 @@ Function Run($payload) {
$ username = $ payload . become_user
$ username = $ payload . become_user
$ password = $ payload . become_password
$ password = $ payload . become_password
# FUTURE: convert to SafeHandle so we can stop ignoring warnings?
Add - Type - TypeDefinition $ helper_def - Debug : $ false
Add - Type - TypeDefinition $ helper_def - Debug : $ false - IgnoreWarnings
# NB: CreateProcessWithTokenW commandline maxes out at 1024 chars, must bootstrap via filesystem
# NB: CreateProcessWithTokenW commandline maxes out at 1024 chars, must bootstrap via filesystem
$ temp = [ System . IO . Path ] : : Combine ( [ System . IO . Path ] : : GetTempPath ( ) , [ System . IO . Path ] : : GetRandomFileName ( ) + " .ps1 " )
$ temp = [ System . IO . Path ] : : Combine ( [ System . IO . Path ] : : GetTempPath ( ) , [ System . IO . Path ] : : GetRandomFileName ( ) + " .ps1 " )