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?
Related
A way to run multiple programs in a bat file.
Objective
Distribute a software with GDAL as a dependency.
To do that I have downloaded gdal binaries from GIS Internals. The downloaded data has a .bat file to set environment variables. It uses set command to set the environment variables.
As per my limited knowledge in windows bash scripting, I understand that the environment variables set by set are limited to current command prompt itself and are reset when a new command prompt is launched.
Also, is it true that a calling a batch file from a batch file launches new command prompt which when closes doesn't affect the next command called in the parent script.
There is another issue here - will the environment variables affect the process created (such as calling gdal_translate) by a Java program? If it doesn't, then there is no point in setting local environment variable.
Final Requirement:
How to use the environment variables set in another batch file (called from a batch file) in the next line of the parent batch file, without using setx?
If you use the CALL command to run the batch file as specified in the accepted answer on the question you linked to, then the environment variables will pass up to the parent batch file.
There are three times where this is not true:
When using SETX neither the parent nor child batch file will get the environment variables.
When using SETLOCAL and ENDLOCAL inside the child batch file the parent batch file will not get the environment variables.
When running the child batch file using start or cmd.exe /c.
So long as you run your Java application in the same environment (i.e. the same batch file), it will pick up the same environment variables. You can verify this with an application like Process Explorer.
Running set _kjhgkjshdgkjhdfg=TEST before running a .jar file resulted in the screenshot below using any of:
javaw -jar jarfile.jar
cmd /c javaw -jar jarfile.jar
start cmd /c javaw -jar jarfile.jar
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
The windows v7.1 SDK has a SetEnv.Cmd script in its binary folder to correctly setup its environment. The problem is this script obviously only works with cmd.exe and I can't find an equivalent for powershell anywhere.
So am I forced to use cmd.exe or is there a way to use powershell (apart from manually rewriting the SetEnv.Cmd script - if even that would work?).
Someone wrote a ps1 script that parses out the SDK's setenv so you can avoid the extra processes:
http://www.tavaresstudios.com/Blog/post/The-last-vsvars32ps1-Ill-ever-need.aspx
You can launch an instance of CMD.EXE, run SetEnv.cmd, and then launch PowerShell from within the CMD window. The PowerShell instance that opens up will import the environment variables from the CMD instance that spawned it.
It's ugly, but it works.
I wrote a batch script to do it for me, and just created a shortcut to it on my desktop. Here's an example:
#echo off
call "C:\Path\To\SetEnv.cmd" param1 param2 param3
powershell.exe -noexit
I would like to write some scripts on powershell, it involve using the environment variable on windows
here is the example of the script
test.ps1
setX number 456
echo $env:number
I found that $env:number cannot be updated immedately on the same session of powershell prompt. I need to reopen the powershell prompt. However, this would break my scripts
How can i update the env variable immedately? In linux it is easy to do with EXPORT command, but for windows, it is a hazard...
In PowerSell environment variables are available through a provider. A provider is a way to manupulation all kind of tree containers. have à look at :
Get-PSProvider
Then drives are entities using these providers. have a look at
Get-PSDrive
You can see that it exists a drive called env
You can try :
Get-childItem env:
to set an environment variables you can write :
$env:mavar = "TESTJPB"
To create more permanent environment variables (i.e., user-level or machine-level) you need to use the .NET Framework and the SetEnvironmentVariable method. For example, this command creates a user-level environment variable named TestVariable:
[Environment]::SetEnvironmentVariable("mavar", "TESTJPB", "User")
Have a look to this Microsoft article.
Have you tried
[environment]::setenvironmentvariable()
I am trying to make a simple script to set my gcc variables. as a .bat file.
the variable is set like this
$env:Path += ";C:\Users\Brett\Compilers\MinGW\bin"
this runs just fine when I type/paste it into power shell.
but when I paste into a script myscript.bat, and run it through powershell I get this error:
C:\Users\Brett\Compilers>"$env:Path += ";C:\Users\Brett\Compilers\MinGW\bin""
The filename, directory name, or volume label syntax is incorrect.
PS C:\Users\Scruffy\Compilers>
PowerShell is a seperate execution enviroment from with Windows Command Line (cmd.exe)
If you want to run powershell commands from a batch file you need to save the powershell script (.ps1) and pass it into powershell.exe as a command line argument.
Example:
powershell.exe -noexit c:\scripts\test.ps1
More Information is available here on Microsoft TechNet
In general, leave batch stuff to .BAT files and put PowerShell stuff into .ps1 files.
I can duplicate your results here - but those are to be expected. Cmd.exe sees a string then a path and then gets quite confused as the syntax is not one that the command prompt can handle. So it gives that error message.
If you want to add stuff to your path, then why not put the statement inside a .ps1 script file?
As mentioned by others, you need to save the code in a .ps1 file and not .bat.
This line (from Setting Windows PowerShell path variable) will do the trick:
$env:Path = $env:Path + ";C:\Users\Brett\Compilers\MinGW\bin"
Or even shorter:
$env:Path += ";C:\Users\Brett\Compilers\MinGW\bin"