It is sometimes interesting to speculate about how unusual feature patterns in
Microsoft projects may reflect the traditions or prejudices of the teams
involved with creating and evolving those projects. Today's example is
"%VS140COMNTOOLS%"..\..\vc\bin\vcvars32.bat
, that wily little batch script
that mucks your command environment enough to enable most Visual Studio
declarative-like thingies to happen (easily) on the command prompt.
So PowerShell has been around for like 17 years now (if you include the Monad
proto period). That's enough time for an effective rewrite or two of the
Visual Studio codebase and yet we're still stuck with this inconvenient script
written in possibly the worst shell still in popular use today. How can we get
it to work with possibly the best shell in popular use today? Unfortunately
there is no single command that will dump the environment of a cmd
subprocess into the parent powershell
environment. I found several hacks
online proposing to do this, the most correct and elegant being
Invoke-Environment.
Note
[Digression] reStructureText's link formatting is egregiously inferior.
What I really wanted was some Groovy code that will dynamically modify the
environment of a declarative pipeline with the results of vcvars32.bat
.
Jenkins pipeline allows for setting environment variables dynamically,
but the dynamism packaged into this feature only allows for arbitrary values
for a set of a priori variable names. The vcvars32.bat
script sets an
indeterminate set of variable names. There may still be a way to do this, but
my Groovy-fu does not show me how to edit the env
object at sufficient
introspection.
Here is the essential functionality of Invoke-Environment
applied to
vcvars32.bat
. This is what I used to prime the PowerShell environment for
Visual Studio work by pasting the code block directly into the powershell()
step before executing Visual Studio commands. This is not the most elegant,
but it is only a few more lines than directly sourcing the batch script and
seems to be the plainest way to absorb its environment.
foreach ($_ in cmd /c "`"%VS140COMNTOOLS%`"..\\..\\vc\\bin\\vcvars32.bat > nul 2>&1 & SET") { if ($_ -match '^([^=]+)=(.*)') { [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2]) } }
Note
If you are using this in a Jenkins pipeline, all $
's will need to be
escaped, \$
, to signify that they signal PowerShell variables and not
Groovy variables. Also `
is PowerShell's escape character, so `"
is an escaped quote.