1

I am calling 64-bit Powershell from a 32-bit C# app using the sysnative redirector, which works fine:

Process proc = new Process();
proc.StartInfo.FileName = @"C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe";
proc.StartInfo.UseShellExecute = false;
proc.Start();

As soon as I add an explicit username/password (even the same one that successfully runs the above), I get a file not found error starting the process:

Process proc = new Process();
proc.StartInfo.FileName = @"C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.WorkingDirectory = "somedir";
proc.StartInfo.UserName = "username";
proc.StartInfo.PasswordInClearText = "somepassword";
proc.StartInfo.Domain = "somedomain";
proc.Start();

Is there some limitation on the sysnative redirector in such a case?

PLK
  • 389
  • 2
  • 13
  • It seems that explicit username/password forces it to be a 64-bit process as `C:\Windows\system32` works in this case and runs 64-bit powershell as desired (even though the calling process is 32-bit). – PLK Jul 21 '19 at 13:08
  • For anyone looking into this, if you don't take care of the Windows station/desktop security as detailed here: https://stackoverflow.com/questions/677874/starting-a-process-with-credentials-from-a-windows-service, the process you start with an explicit username/password using this API will hardly be able to do anything and will likely fail in various mysterious ways. – PLK Jul 21 '19 at 13:11

1 Answers1

0

When you set UseShellExecute = false;, Process.Start() will call kernel32!CreateProcess, rather than shell32!ShellExecute, and only the latter seems to resolve the sysnative reference correctly.

To get around this, disable SysWOW64 redirection for the current thread temporarily:

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool Wow64DisableWow64FsRedirection(ref IntPtr oldValue);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool Wow64RevertWow64FsRedirection(IntPtr oldValue);

// Disable redirector
IntPtr oldValue = IntPtr.Zero;
Wow64DisableWow64FsRedirection(ref oldValue);

try
{
    // Start your process while fs redirector is disabled
    process.Start()
}
catch (Exception ex)
{
    // Handle ex if necessary, error logging, otherwise re-throw
    throw;
}
finally
{
    // Make sure you revert redirection settings again
    Wow64RevertWow64FsRedirection(oldValue);
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • I'm not sure that's true as the first case I mentioned works fine with `UseShellExecute=false` - the `Sysnative` redirector is found and works fine. It seems to be something to do with the fact that without explicit username/password, it starts a 32-bit process (the web app this code is inside is 32-bit) but with username/password, it's 64-bit (because the OS is 64-bit?) and hence the redirector isn't there. – PLK Jul 21 '19 at 10:17