Running VS 2017 Build Tools in Windows PowerShell - windows

I dislike IDEs, so I installed the VS 2017 Build Tools so I can work via command-line.
The install went fine, and everything works out of Windows CMD, however, PowerShell is much better, and I prefer to use PS. The issue here is that according to MSDN:
The Visual C++ command-line tools use the PATH, TMP, INCLUDE, LIB, and LIBPATH environment variables, and may also use tool-specific environment variables. Because the values of these environment variables are specific to your installation, and can be changed by product updates or upgrades, we recommend that you use vcvarsall.bat or a Developer Command Prompt shortcut instead of setting them yourself. For information about the specific environment variables used by the compiler and linker, see CL Environment Variables and LINK Environment Variables.
I shouldn't set the Environment Variables myself, and that's fine with me, the only issue is that when I run the vcvarsall.bat in PS, no environment variables change. I am new to PS, so I'm guessing that .bat files can't alter session environment variables. If that's the case, then I can't work out of PS. As a side note, the CL and LINK variables never show up, I'll explain below.
I figured I should find out what the variables are. I echoed all my variables to a text file before and after running the batch file, and wrote a short Java program to find anything new, or modified. These are them. As you can see the CL and LINK variables are not present.
How do I solve this issue? I was thinking of writing my own batch file, but if the first one didn't work, why would mine? I didn't see anything on the attached MSDN page, or any links there about how to make this work for PowerShell.

Write a batch file that 1) invokes vcvarsall.bat, and 2) invokes PowerShell, like so (this one is specific to VS 2015):
#CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %*
#start powershell
%* allows us to pass the same arguments to this file as you would to vcvarsall.bat.
PowerShell will then run with the environment block prepared for it. The other way around doesn't work because PowerShell doesn't execute batch files itself -- it relies on cmd to do that, and as a child process, that has its own environment block that doesn't reflect on its parent.

<#
.SYNOPSIS
Invokes the specified batch file and retains any environment variable changes it makes.
.DESCRIPTION
Invoke the specified batch file (and parameters), but also propagate any
environment variable changes back to the PowerShell environment that
called it.
.PARAMETER Path
Path to a .bat or .cmd file.
.PARAMETER Parameters
Parameters to pass to the batch file.
.EXAMPLE
C:\PS> Invoke-BatchFile "$env:ProgramFiles\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
Invokes the vcvarsall.bat file. All environment variable changes it makes will be
propagated to the current PowerShell session.
.NOTES
Author: Lee Holmes
#>
function Invoke-BatchFile
{
param([string]$Path, [string]$Parameters)
$tempFile = [IO.Path]::GetTempFileName()
## Store the output of cmd.exe. We also ask cmd.exe to output
## the environment table after the batch file completes
cmd.exe /c " `"$Path`" $Parameters && set " > $tempFile
## Go through the environment variables in the temp file.
## For each of them, set the variable in our local environment.
Get-Content $tempFile | Foreach-Object {
if ($_ -match "^(.*?)=(.*)$") {
Set-Content "env:\$($matches[1])" $matches[2]
}
else {
$_
}
}
Remove-Item $tempFile
}
$VcVars = 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Auxiliary\Build\vcvarsall.bat'
Invoke-BatchFile $VcVars x64
cl hello_world.cpp

Related

ILDASM could not be found in the PowerShell window of Visual Studio 2019

Trying to follow tutorial steps and disassemble an executable c# file but whenever i type ildasm on the command prompt it says not recognized in a developer powershell. Shows the same message when i do it for dll file as well. please help.
The error message implies that ildasm.exe's directory isn't among the list of directories stored in the $env:PATH environment variable, so you cannot invoke it by name only.
To invoke it by its path from PowerShell, there's an additional syntactic requirement: invoking executables by paths that require quoting - such as in your case, given that the path contains spaces - requires calling via &, the call operator:
# Add arguments as needed.
& 'C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\ildasm.exe'
To add ildasm.exe's directory to your $env:PATH variable, run the following:
$env:PATH += ';C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools'
This only stays in effect for the remainder of the current session.
If you want to it to take effect in future PowerShell sessions by default, run the following once, then start a new session. The command adds the $env:PATH-extending command to your PowerShell profile file, $PROFILE, which is loaded automatically when a session starts:
if (-not (Test-Path $PROFILE)) { New-Item -Force $PROFILE }
Add-Content $PROFILE -Value '$env:PATH += ";C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools"'
If you want the change to take effect system-wide (in future sessions), you need to update the persistent definition of the PATH environment variable, which is stored in the registry; run the following once, then start a new PowerShell session.
[Environment]::SetEnvironmentVariable(
'Path',
(
[Environment]::GetEnvironmentVariable('Path', 'User') +
';C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools'
),
'User'
)
The above modifies the persistent PATH environment variable for the current user.
To modify the definition for all users, replace both instances of 'User' with 'Machine', but note that you must then run the command from an elevated session (run as admin).

Reuse variables from cmd in powershell

I'm having problems accessing environment variables I set in cmd in PowerShell.
I want to overwrite the variable PROCESSOR_ARCHITECTURE from x86 to AMD64. For this case I have a cmd script "test.cmd" that has the following content:
set PROCESSOR_ARCHITECTURE=AMD64
call powershell %~dp0\test.ps1
As you can see, I'm calling a PowerShell script called test.ps1 in the same folder with the following content:
echo $env:PROCESSOR_ARCHITECTURE
Unfortunately that prints the following:
x86
I think PowerShell takes a fresh copy of the global environment variables instead of using the modified set from the cmd it was invoked from.
Is there a way to use the modified value of PROCESSOR_ARCHITECTURE in my PowerShell script without the use of parameters?

How can I use the cl command on PowerShell?

I am unable to use the cl command in PowerShell.
I tried to add the following command to my PowerShell profile to exec vcbuildtools.bat, but PowerShell does not recognize cl command on PowerShell?
&"C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat"
OS: Windows 10
Just to be clear I'm addressing the asker's issue that cl is not in the PATH even after running this in PowerShell
&"C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat"
I think this boils down to the issue that batch file can't export variables to PowerShell (also related: this question), as you've found out with vcbuildtools.bat. I think it's because PowerShell invokes a cmd.exe subshell to execute the batch file which changes the environment in the subshell but the changes don't propagate to the parent shell i.e. PowerShell.
Solution 1
One way is to use the fact that subshell inherits the environment from the parent shell. So if you run this in PowerShell, the environment set by the batch file is preserved
cmd.exe /k "C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat" `& powershell
Take note of `&. The character has to be escaped because it has a special meaning in PowerShell.
Solution 2
The Pscx module has an Import-VisualStudioVars function which imports environment variables for Visual Studio. An example usage is
Import-VisualStudioVars 2015 amd64
if you're using VS/BuildTools 2015 and compiling 64-bit programs. You can use Pop-EnvironmentBlock to revert the changes. See man Import-VisualStudioVars -full for more information.
Alternatively, Pscx also has an Invoke-BatchFile function that retains environment changes by a batch file. An example usage
Invoke-BatchFile "C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat"
See man Invoke-Batchfile -full for more information.
Notes
To download the up-to-date version of Pscx from PowerShell gallery, you will need PowerShellGet which is shipped with PowerShell 5 and is available as a downloadable installer for PowerShell 3 and 4.
For those with PowerShell 1 and 2, older versions of Pscx is available on Codeplex.
You can use the following function to invoke a cmd.exe shell script (batch file) and persist its environment variables:
function Invoke-CmdScript {
param(
[String] $scriptName
)
$cmdLine = """$scriptName"" $args & set"
& $env:SystemRoot\system32\cmd.exe /c $cmdLine |
Select-String '^([^=]*)=(.*)$' | ForEach-Object {
$varName = $_.Matches[0].Groups[1].Value
$varValue = $_.Matches[0].Groups[2].Value
Set-Item Env:$varName $varValue
}
}
Add this function to your PowerShell profile, and run the batch file using the function:
Invoke-CmdScript "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\vsvars32.bat"
Fortunately, VS 2019 Community now has a Developer PowerShell for VS 2019 command.
The actual command, if you want to see the properties for the shortcut, is rather verbose.
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -noe -c "&{Import-Module """C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"""; Enter-VsDevShell 14bbfab9}"
Anyway, I am using this and it adds the right cl.exe to my path, but there is an odd message after running it:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\ostream(750): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
.\hey.cpp(4): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)' being compiled
Another option from PowerShell gallery:
posh-vs
Makes Visual Studio command line tools available in PowerShell. Supports Visual Studio 2017 and 2015.
I also encountered the same problem, type cmd.exe and you'll change control to command line.
PowerShell example
If you want to go back to PowerShell, no problem. Just write exit. As simple as it sounds

Microsoft Word Command line Utility

I have a MS Word document whose path is set in the Environment variable.
How to open that document from Command line Utility?
"C:\Program Files\Microsoft Office\Office\Winword.exe" E:\hello.docx
I have the above command to open a document. But in the above command I have hardcoded the document's name and path.
All I want to do is to use an Environment variable to supply the document's name and path.
If you're open to using Powershell instead of the command prompt, you can complete with just a couple of setup steps.
First, create the environment variable for your word document. If you've already done this elsewhere, skip this step. Note that strings that are enclosed by double quotations will resolve variables, so in this example $env:username will resolve to your current Windows user. You could hard-code that too if you like, but this is helpful to generalize the example.
$env:WordDoc = "C:\Users\$env:username\Documents\myDocument.docx"
Next, you will need to add Office's directory to your path variable. You can search for winword.exe to find the location, but it will probably be one of the two below:
C:\Program Files\Microsoft Office\Office14
C:\Program Files (x86)\Microsoft Office\Office14
You can simply append that path to the environment variable, like so:
$env:Path += ";C:\Program Files\Microsoft Office\Office14"
Anyway, once that is set you can use winword from powershell to open word documents. Here's a simple example:
winword $env:WordDoc
A quick note about changing environment variables in this manner -- they are on the process level. That means that these changes will go away when you close your powershell session. Instead of typing them out each new session, you could save them to a powershell script and run that in the console. Here's a quick script that works on my machine:
param
(
[string]$FilePath
[string]$wordDir = "C:\Program Files (x86)\Microsoft Office\Office14"
)
$env:WordDoc = $FilePath
If(!($env:Path | Select-String -SimpleMatch $wordDir))
{
$env:Path += ";$wordDir"
}
winword $env:WordDoc
Doing this in the command prompt would involve a similar procedure -- you still need to set your PATH environment variable to recognize Microsoft Office. This answer offers some insight on how to do that.
If you mean from a batch file, and MS Word is properly associated with the .doc and .docx file extensions on your system, it's very simple.
Put the following in a batch file (for instance, C:\Temp\StartHello.bat). I've used DocVar to be the path and filename of the document; replace it with whatever your environmental variable is named.
set DocVar="E:\Hello.docx"
%DocVar%
Run it
C:\Temp>StartHello
If the environmental variable is already set, just remove the first line from the batch file that assigns it. This leaves you with a single line:
%DocVar%
If you mean "directly from the command line", you can just skip the batch file part:
C:\Temp>%DocVar%

Calling batch files with make and making changes persistent

I'm programming with Visual C++ Express on the command line using makefiles (GNU Make).
For this to work, I have to call the Visual Studio batch file vsvars32.bat to set up the environment. This has to be done everytime I open a new cmd.exe, before using make.
When I try to call the batch file from my makefile, it obviously executes the batch file as
an own process, because the environment is the same afterwards.
So my question: is there a way to execute scripts in cmd.exe like the built-in source command of the Linux/Unix bash? Apart from installing bash on Windows, of course.
Edit after posting my own answer:
The above question is not quite right, it should be like this:
Is it possible to call an environment-changing batch file from within a makefile, so that the changed environment persists for the other programs called in the makefile?
The answer to the original question is yes: you can use the built-in call command of cmd.exe. But since call is a built-in command and not a real program, it doesn't work in a makefile, only if you call a batch file from another batch file.
Answer compiled from the previous answers:
I made a batch file called make.bat which contains the following:
call "%VS90COMNTOOLS%vsvars32.bat"
call make.exe %*
This does the job.
But calling an environment-changing batch file from within a makefile, so that the changed environment persists for the other programs called in the makefile, seems to be impossible.
Edit: After overflowing my PATH variable by repeatedly calling vsvars32.bat, I made the following changes:
if not "%VISUALCVARS%" == "TRUE" (
set VISUALCVARS=TRUE
call "%VS90COMNTOOLS%vsvars32.bat"
)
call make.exe %*
use 'Call':
#echo off
pushd.
call "C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars3235.bat"
msbuild LinqSupportClassesSDKBuild.csproj /t:rebuild /p:Configuration=Release /nologo /v:q /clp:ErrorsOnly;
popd
this is the cmd file we use to build our linq provider.
At least in my install of Visual Studio (albeit somewhat ancient VS .NET 2003), one of the links in the VS start menu group is to open a cmd.exe instance with the environment already setup. You might find these helpful:
How to Add Visual Studio Command Prompt (VSCP) to your IDE as a tool?
Running the command prompt from visual studio tools menu
Shortcut: Launch Visual Studio Command Prompt from Visual Studio
They are more geared toward launching the command prompt from the IDE, but they do include information on launching it with the appropriate environment as well which you may find helpful for your purposes.
How do you launch your console? If you are just launching 'cmd' then instead, create a shortcut that executes (%comspec% resolves to c:\windows\cmd.exe or whatever is relevent on your system)
%comspec% /k ""C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"" x86
Obviously, change the path to point to the proper installation folder.
More generally, as the above poster pointed out, if a .cmd file needs to process another .cmd file rather than launch it as a seperate process, use the 'call' batch command.
Wrap GNU make in a script (mmake.bat). Put the script in the path somewhere.
The script itself should run the vsvars32.bat and then make, like this
vsvars32.bat
make %*
As far as I remember, invoking a script from another script like this is done within the same shell (similar to Bash "." command).
I have found three solutions to this problem:
1) If the environment variables being set by the batch file are static (that is, they are always the same values), set those values for your entire user profile. Right-click on My Computer, click Properties-->Advanced-->Environment Variables. Add the variables from the batch file to the User Variables or System Variables section (User variables are only visible by you, System variables are visible by all users of that computer).
2) Write a wrapper batch file that calls the environment setup script then calls the Makefile.
3) Instead of using the SET command to set environment variables in the batch file, use the SETX command (requires the Windows Resource Kit). SETX is similar to SET, except it makes its changes to the master environment in the registry and will take effect in all command prompts launched in the future (but not the current one).

Resources