11

Is there a way to push and pop all environment variables in a batch script? For example I would like to do something like this:

pushEnvironmentVariables
call "%VS140COMNTOOLS%\vsvars32.bat"
(do some stuff...)
popEnvironmentVariables
pushEnvironmentVariables
call "%VS90COMNTOOLS%\vsvars32.bat"
(do some other stuff...)
popEnvironmentVariables

2 Answers 2

14

Use setlocal, see setlocal /? or ss64.com/nt/setlocal

Setlocal
call "%VS140COMNTOOLS%\vsvars32.bat"
(do some stuff...)
Endlocal
Setlocal
call "%VS90COMNTOOLS%\vsvars32.bat"
(do some other stuff...)
Endlocal

To save the current variable state you could do

set >MyVarStatus.txt

and restore later on with

@Echo off
For /f "tokens=1* delims==" %%A in (
  'findstr /V "^Path" MYVarStatus.txt '
) Do Set %%A=%%B

this would exclude the Path variables.

5
  • You exclude PATH -- just for example or for some reason. I'm especially interested in push/pop the path variable. Is there anything that speaks against backup/restore PATH?
    – Wolf
    Jun 14, 2017 at 12:17
  • In fact both, an example and in case important changes were applied to the path in the meantime a precaution. @wolf
    – LotPings
    Jun 14, 2017 at 12:21
  • Well, you cannot be sure in all cases, but if you have to add something to the path for a specific session only, you are definitely interested in restoring the path afterwards. You'd not have to do this if there weren't external tools that call other tools and expecting them to be in the path.
    – Wolf
    Jun 14, 2017 at 12:24
  • 1
    The code is open to changes, if one wants to restore the whole environment simply replace findstr with type.
    – LotPings
    Jun 14, 2017 at 12:29
  • Thanks, I just wanted to be sure not to overlook anything important.
    – Wolf
    Jun 14, 2017 at 12:52
1

A bit late to the scene but here goes anyways. Below is an implementation of a stack data structure in Windows batch scripting.

Features:

  • You must call the :InitializeStack subroutine before using the stack.
  • Push items on the stack by calling the :Push subroutine.
  • Pop items off the stack by calling the :Pop subroutine.
  • The variable $Count will always contain the count of items in the stack.
  • The variable $Top will always contain the most recent item added to the stack.
  • The variable $Bottom will always contain the first item added to the stack.
  • You can dump the content of the stack by calling the :DumpStack subroutine.
  • The type of items that you can push on the stack is anything that can be stored in a variable. For example, Call :Push "String 1", Call :Push "%1", Call :Push "%MyVariable%", etc.

I use the stack in my batch files to keep track of subroutine calls. Every subroutine in my batch files starts with Call :Push %0, which pushes the current subroutine's name onto the stack and ends with Call :Pop.

Some may find it an over-kill for batch scripting but I enjoyed creating it and I hope someone will find this useful, enjoy.

@Echo Off
Cls
SetLocal
SetLocal EnableExtensions
SetLocal EnableDelayedExpansion

Call :InitializeStack

Call :Push "String 1"
Call :Push "String 2"
Call :Push "String 3"
Call :Pop

Echo Total items in stack = !$Count!
Echo Top of stack         = !$Top!
Echo Bottom of stack      = !$Bottom!
Call :DumpStack

Goto End

:InitializeStack
:------------------------------------------------------------
Set "$Stack[0]=0"
Set "$Count=!$Stack[0]!"
Set "$Top="
Set "$Bottom="
Exit /b

:DumpStack
:------------------------------------------------------------
If !$Stack[0]! EQU 0 (
  Echo Stack is empty.
) Else (
  Echo.
  Echo Stack Dump
  Echo ----------
  For /l %%a In (!$Stack[0]!,-1,1) Do (Echo !$Stack[%%a]!)
)
Exit /b

:Push <String>
:------------------------------------------------------------
Set /a "$Stack[0]+=1"
Set "$Count=!$Stack[0]!"
Set "$Top=%~1"
Set "$Bottom=!$Stack[1]!"
Set "$Stack[!$Stack[0]!]=!$Top!"
Exit /b

:Pop
:------------------------------------------------------------
If !$Stack[0]! EQU 0 (
  Echo "Stack is empty."
) Else (
  Set "$Stack[!$Stack[0]!]="
  Set /a "$Stack[0]-=1"
  Set "$Count=!$Stack[0]!"
  If !$Stack[0]! GTR 0 (
    For %%a In (!$Stack[0]!) Do Set "$Top=!$Stack[%%a]!"
    Set "$Bottom=!$Stack[1]!"
  ) Else (
    Set "$Top="
    Set "$Bottom="
  )
)Exit /b

:PushAllEnvironmentVariables
:------------------------------------------------------------
For /f "Tokens=* Delims=" %%a In ('Set') Do Call :Push "%%a"
Exit /b

:PopAllEnvironmentVariables
:------------------------------------------------------------
For /l %%a In (!$Stack[0]!,-1,1) Do (Set !$Stack[%%a]!)
Exit /b

:End

So, to push all environment variables you can call :PushAllEnvironmentVariables, to restore all environment variables, you can call :PopAllEnvironmentVariables

2
  • This looks —at a glance— to be something that maybe took some effort to develop, and maybe could be useful to somebody.  Can you explain how this provides an answer to this question? Aug 7, 2019 at 6:05
  • I see your point, to push all environment variables you can use: For /f "Tokens=* Delims=" %%a In ('Set') Do Call :Push "%%a" To restore all environment variables you can use: For /l %%a In (!$Stack[0]!,-1,1) Do (Set !$Stack[%%a]!) I have updated the answer to include 2 subroutines that implements this.
    – Safwan
    Aug 8, 2019 at 8:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.