"File not found" error launching system32\winsat.exe using Process.Start()
Asked Answered
J

2

6

I'm trying to run the Windows System Assessment Tool (winsat.exe) using the following code:

System.Diagnostics.Process WinSPro =
    new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo WinSSInfo = 
    new System.Diagnostics.ProcessStartInfo();
WinSSInfo.FileName = "cmd.exe";
WinSSInfo.Arguments = "/k winsat.exe";
WinSPro.StartInfo = WinSSInfo;
WinSPro.Start();

This code works if I only call cmd.exe, and even if I call regedit.exe it still works. However, when I try to call winsat.exe as a argument of cmd.exe, it fails. The command prompt shows this:

'winsat.exe' is not recognized as an internal or external command, 
operable program or batch file.

I tried several ways to call winsat.exe:

  1. Call it directly by assigning "winsat.exe" to ProcessStartInfo.FileName. It fails with a Win32Exception: The system cannot find the file specified

  2. As above, using the full path - @"c:\windows\system32\winsat.exe". It fails with the same error.

  3. Run the code as the System Administrator. It still fails.

  4. Call winsat.exe as in the coded example. It failed as I explained earlier.

It's interesting that the command prompt launched from the code can only see .dll files in c:\windows\system32.

Does anyone have any idea why winsat.exe cannot be launched through System.Diagnostics.Process? Are there any limitations which I've misunderstood?

Thanks,

Rex

Jeu answered 30/5, 2013 at 2:56 Comment(2)
what is the use of winsat.exe ?Soteriology
winsat.exe is the system command to run Windows Experience Index.Jeu
A
12

winsat.exe is redirected using Windows-on Windows 64-bit redirection. What's happening is that your launch request (from a 32-bit process) is being redirected to %windir%\SysWOW64\winsat.exe. Since there's no 32-bit version of this particular executable on 64-bit installs, the launch fails. To bypass this process and allow your 32-bit process to access the native (64-bit) path, you can reference %windir%\sysnative instead:

Process WinSPro = new Process();
ProcessStartInfo WinSSInfo = new ProcessStartInfo();
WinSSInfo.FileName = @"c:\windows\sysnative\winsat.exe";
WinSPro.StartInfo = WinSSInfo;
WinSPro.Start();

Alternatively, if you build your program as x64, you can leave the path as c:\windows\system32.

Note that it's best to use Environment.GetFolderPath to get the path to the windows directory, just in case the OS is installed in a non-standard location:

WinSSInfo.FileName = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.Windows),
    @"sysnative\winsat.exe");
Aves answered 30/5, 2013 at 3:56 Comment(0)
G
2

Based on Simon MᶜKenzie's answer, and the link he provided (thanks to soyuz for his comment) I wrote method that should work in either cases (to just copy/paste the code):

public static string GetSystem32DirectoryPath()
{
    string winDir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
    string system32Directory = Path.Combine(winDir, "system32");
    if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
    {
        // For 32-bit processes on 64-bit systems, %windir%\system32 folder
        // can only be accessed by specifying %windir%\sysnative folder.
        system32Directory = Path.Combine(winDir, "sysnative");
    }
    return system32Directory;
}

and code to launch the process:

var pi = new ProcessStartInfo
{
    FileName = Path.Combine(GetSystem32DirectoryPath(), "winsat.exe"),
    CreateNoWindow = true,
    UseShellExecute = false
};
Process.Start(pi);
Gesundheit answered 26/6, 2014 at 9:21 Comment(1)
I don't like this solution for its hardcoded strings and an approach that differentiates between 32 and 64 bit when the WoW mechanism should be designed to do just that transparently for us. In the end I had to upvote because it was the only answer that worked for me.Amnion

© 2022 - 2024 — McMap. All rights reserved.