Home > Enterprise >  Why does powershell say cl.exe is not recognized?
Why does powershell say cl.exe is not recognized?

Time:07-10

I have visual studio installed, and cl.exe runs perfectly fine after vcvarsall.bat has been run in cmd but in powershell it says it is not recognized. cmd.exe

C:\Users\Ethos>vcvarsall.bat x64
**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.2.5
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

C:\Users\Ethos>cl
Microsoft (R) C/C   Optimizing Compiler Version 19.32.31332 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

The above works fine in cmd.

PS C:\Users\Ethos> vcvarsall.bat x64
**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.2.5
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
PS C:\Users\Ethos> cl
cl : The term 'cl' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
  cl
  ~~
      CategoryInfo          : ObjectNotFound: (cl:String) [], CommandNotFoundException
      FullyQualifiedErrorId : CommandNotFoundException

The above happens in power. Does anyone know why this happens or how to fix it?

CodePudding user response:

Note:

  • The following assumes that there isn't also a vcvarsall.ps1 PowerShell script file, i.e. the PowerShell equivalent to the vcvarsall.bat batch file.

  • If vcvarsall.ps1 exists, simply call it instead (.\vcvarsall.ps1 if located in the current dir, just vcvarsall.bat if located in one of the dirs. in $env:PATH)

    • If it doesn't exist consider wrapping one of the solutions below in a PowerShell function that you can place in your $PROFILE file; e.g.:

      function vcvarsall {
        cmd /c vcvarsall.bat @args '&&' (Get-Process -Id $PID).Path        
      }
      

From PowerShell, run the following (assuming that vcvarsall.bat is either in the current directory or in a directory listed in $env:PATH):

cmd /c vcvarsall.bat x64 '&&' (Get-Process -Id $PID).Path

This instructs cmd.exe to define the environment variables and then launches another PowerShell session that inherits those environment variables.

Note that the original PowerShell session will live on (as does cmd.exe, but it exits automatically when the nested PowerShell session ends), so when you exit the nested PowerShell session, you'll return to the original one.


Alternatively, if you prefer to start the new PowerShell session in a new window, call via cmd.exe's start command:

cmd /c "vcvarsall.bat x64 && start `"$([Console]::Title)`" `"$((Get-Process -Id $PID).Path)`""

As for what you tried:

For batch file vcvarsall.bat to be effective, it must define environment variables for the current process.

This works from cmd.exe, because batch files execute in-process there.

By contrast, PowerShell must run batch files in a cmd.exe child process, as it cannot interpret batch files itself.
However, environment variables defined in a child process are not seen by the calling process.

Therefore, the above solutions launch an aux. cmd.exe process first, which defines the environment variables for itself, and then launches a new PowerShell session which inherits those environment variables.

  • Related