Skip to content

Commit fcff70a

Browse files
totekuhclaude
andcommitted
Bump to v2.1 with quality-of-life improvements
- Add --version/-V flag - Fix pipe output to loop until EOF (no more silent truncation >1MB) - Remove leading blank line from captured output - Propagate child exit code in all modes, not just passthrough Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e772ec6 commit fcff70a

3 files changed

Lines changed: 17 additions & 10 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# RunEx v2.0
1+
# RunEx v2.1
22

33
Run processes as another user. Works from interactive and service contexts, handles window station DACLs, redirects I/O. Supports `/netonly` logon for running AD tooling from non-domain-joined machines.
44

src/Program.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
public static class RunExMainClass
66
{
77
private static readonly string help = @"
8-
RunEx v2.0 - @totekuh
8+
RunEx v2.1 - @totekuh
99
1010
Usage:
1111
RunEx.exe username password cmd [args...] [options]
@@ -30,6 +30,7 @@ RunEx.exe user pass -l 8 -- cmd /c echo -v
3030
Options:
3131
-h, --help show this help message and exit
3232
--help-all show extended reference (all logon types, etc.)
33+
-V, --version show version and exit
3334
-d, --domain <domain> domain of the user, if in a domain (default: """")
3435
-l, --logon-type <type> logon type for the new process token (default: 2)
3536
Accepts a number or name alias. See guide below.
@@ -265,6 +266,10 @@ public static string RunExMain(string[] args)
265266
}
266267
switch (args[ctr])
267268
{
269+
case "-V":
270+
case "--version":
271+
return "RunEx v2.1";
272+
268273
case "-h":
269274
case "--help":
270275
case "/?":
@@ -381,8 +386,7 @@ public static string RunExMain(string[] args)
381386
output = String.Format("{0}", e.Message);
382387
}
383388

384-
if (passthrough)
385-
Environment.ExitCode = invoker.ExitCode;
389+
Environment.ExitCode = invoker.ExitCode;
386390

387391
return output;
388392
}

src/RunEx.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ private bool CreateAnonymousPipeEveryoneAccess(ref IntPtr hReadPipe, ref IntPtr
3939

4040
private string ReadOutputFromPipe(IntPtr hReadPipe)
4141
{
42-
string output = "";
42+
StringBuilder sb = new StringBuilder();
4343
uint dwBytesRead = 0;
4444
byte[] buffer = new byte[NativeMethods.BUFFER_SIZE_PIPE];
45-
if(!NativeMethods.ReadFile(hReadPipe, buffer, NativeMethods.BUFFER_SIZE_PIPE, out dwBytesRead, IntPtr.Zero)){
46-
output += "No output received from the process.\r\n";
45+
while (NativeMethods.ReadFile(hReadPipe, buffer, NativeMethods.BUFFER_SIZE_PIPE, out dwBytesRead, IntPtr.Zero) && dwBytesRead > 0)
46+
{
47+
sb.Append(Encoding.Default.GetString(buffer, 0, (int)dwBytesRead));
4748
}
48-
output += Encoding.Default.GetString(buffer, 0, (int)dwBytesRead);
49-
return output;
49+
return sb.ToString();
5050
}
5151

5252
private IntPtr ConnectRemote(string[] remote)
@@ -595,7 +595,10 @@ public string RunAs(string username, string password, string cmd, string domainN
595595
this.hOutputWrite = IntPtr.Zero;
596596
this.hErrorWrite = IntPtr.Zero;
597597
NativeMethods.WaitForSingleObject(processInfo.process, processTimeout);
598-
output += "\r\n" + ReadOutputFromPipe(this.hOutputRead);
598+
uint pipeExitCode = 0;
599+
NativeMethods.GetExitCodeProcess(processInfo.process, out pipeExitCode);
600+
this.ExitCode = (int)pipeExitCode;
601+
output += ReadOutputFromPipe(this.hOutputRead);
599602
} else {
600603
int sessionId = System.Diagnostics.Process.GetCurrentProcess().SessionId;
601604
if (remoteImpersonation)

0 commit comments

Comments
 (0)