PowerShell Cookbook

Search

Categories

 

On this page

Archive

Blogroll

Disclaimer
I work for Microsoft.

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 216
This Year: 16
This Month: 0
This Week: 0
Comments: 523

Sign In

 Wednesday, May 10, 2006
Thursday, May 11, 2006 6:24:19 AM (Pacific Daylight Time, UTC-07:00) ( )

Raymond recently wrote a post titled, “A new scripting language doesn’t solve everything.”  In that post (and in a previous one,) he points out that backwards compatibility is extremely important for cmd.exe (with itself,) and for PowerShell (with existing cmd.exe scripts.)  More importantly, the point is that PowerShell doesn’t solve everything:

Shipping a new command shell doesn't solve everything either. For one thing, you have to decide if you are going to support classic batch files or not. Maybe you decide that you won't and prefer to force people to rewrite all their batch files into your new language. Good luck on that.

On the other hand, if you decide that you will support batch files after all, then presumably your new command shell will not execute old batch files natively, but rather will defer to CMD.EXE. And there's your problem: You see, batch files have the ability to modify environment variables and have the changes persist beyond the end of the batch file.


Similar threads have come up in the newsgroups in relation to VBScript.

Raymond is absolutely correct, and you won’t find a single person on the PowerShell team that says otherwise.  Or has ever said otherwise, for that matter.  PowerShell is not a swap-in replacement for cmd.exe, it is not a swap-in replacement for the Windows Scripting Host, does not need to re-implement every command-line tool that ships in Windows, and does not solve world hunger.  Tensions that suggest differently are misguided.

Many people – and many systems – depend on the subtle details of the tool with which they’ve chosen to solve their problem.  If you want to write an application that understands the source files for all related technologies (ie: cmd.exe scripts, or .vbs files,) then you’d better make sure that you re-implement every nuance and bug as well.  That includes the bugs that even the owners of those related technologies don’t know about, because I guarantee that a script somewhere depends on it.

The solution isn’t to burn your time by rewriting your systems, either.  If you have code that works – keep it!  I currently have files from 41 different technologies in my “tools” directory:

[D:\lee\tools]
PS:170 > dir | group Extension | sort -desc Count

Count Name                      Group
----- ----                      -----
  275 .exe                      {adlb.exe, ansi2knr.exe, atmar
   59 .ps1                      {#share-file.ps1, backup-chang
   39 .bat                      {articlecounter.bat, c.bat, ch
   25 .dll                      {acctinfo.dll, AutoItX3.dll, B
   20 .cmd                      {d.cmd, devdiv.cmd, dumpfsmos.
   16 .vbs                      {checkrepl.vbs, clean.vbs, clo
    8 .js                       {calc.js, cio.js, d2.js, evt2c
    7                           {%backup%~, 0, _viminfo, autom
    6 .config                   {cordbg.exe.config, perfcompar
    5 .hlp                      {depends.hlp, srvmgr.hlp, usrm
    5 .ini                      {KeePass.ini, memtriage.ini, r
    5 .txt                      {cmgetcer.txt, getcm.txt, inst
    4 .doc                      {kernrate.doc, mqcast.doc, prn
    4 .inf                      {clusfileport.inf, clusfilepor
    3 .reg                      {intfiltr.reg, samplereasons.r
    3 .chm                      {clusterrecovery.chm, eventcom
<snip>

Rewriting for the sake of rewriting provides a poor return on investment – interop is the key word here.  If you want to extend your existing systems, you can do that in the tool of your choice.  Most systems can be extended to include other technologies – a typical Windows build, for example, takes advantage of dozens of different tools.  If you want to write new scripts or systems, you can also do that in the tool of your choice. 

In both cases, PowerShell happens to be a tool that solves certain problems extremely efficiently.

To address one specific detail in Raymond’s post,

“You see, batch files have the ability to modify environment variables and have the changes persist beyond the end of the batch file.”

Try this script.  From a PowerShell.exe window, this wrapper script allows you to run batch files that persistently modify their environment variables.

############################################################################## 
## 
## Invoke-CmdScript.ps1 
## 
## Invoke the specified batch file (and parameters), but also propigate any 
## environment variable changes back to the PowerShell environment that 
## called it. 
## 
## ie: 
## 
## PS > type foo-that-sets-the-FOO-env-variable.cmd 
## @set FOO=%* 
## echo FOO set to %FOO%. 
##  
## PS > $env:FOO 
##  
## PS > Invoke-CmdScript "foo-that-sets-the-FOO-env-variable.cmd" Test
##  
## C:\Temp>echo FOO set to Test. 
## FOO set to Test. 
##  
## PS > $env:FOO 
## Test 
## 
############################################################################## 

param([string] $script, [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 /c " `"$script`" $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
    }


Remove-Item $tempFile


[Edit: Updated to make more usable for commands with spaces in their names.]

Comments [6] | | # 
Thursday, July 13, 2006 4:23:57 AM (Pacific Daylight Time, UTC-07:00)
PSMDTAG:PHILOSOPHY: PowerShell is not a drop-in replacement for CMD.EXE

PSMDTAG:PHILOSOPHY: PowerShell does not solve world hunger.

PSMDTAG:PHILOSOPHY: When to rewrite an existing function in PowerShell.

PSMDTAG:FAQ: How can I pick up changes to environment variables after I run a .BAT file?

PSMDTAG:DOTNET: [IO.PATH]::GetTypeFileName()

Jeffrey Snover [MSFT]
Windows PowerShell/Aspen Architect
Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx
Jeffrey Snover
Monday, November 20, 2006 4:47:42 PM (Pacific Standard Time, UTC-08:00)
This script doesn't seem to handle long filename parameters - or batch scripts that call other batch scripts.

I wanted to use it to turn my PowerShell into a Visual Studio 2005 Command Prompt (a common task for developers, I would assume).
I many permutations of the following command, with no luck:
. invoke-cmdscript "C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat" x86

Finally, I had to settle for adding the following to my $profile:
pushd "C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\"
.$home\invoke-cmdscript.ps1 vsvars32.bat
popd

Is there a more elegant solution? Or am I trying to do something I shouldn't?
Monday, November 20, 2006 4:51:15 PM (Pacific Standard Time, UTC-08:00)
Actually, it all needs to be in quotes. The comment header shows an example of a script that takes arguments.
Friday, January 12, 2007 2:53:24 PM (Pacific Standard Time, UTC-08:00)
Yeah, it's great to have the "opportunity" to juggle 7 text editors, 4 shells, 5 MUAs, ... everyone loves that part of computing.

But you're right, if you can't solve world hunger, why try to make powershell a complete replacement to cmd.exe. I mean, that must be so hard, cmd.exe being generally recognized as such a full fledged shell with heaps of possibilities...

</sarcasm and stuff>

Seriously, what is the best way of getting vs.net env vars into powershell?

*and I return to my google journey*
Friday, January 12, 2007 9:10:59 PM (Pacific Standard Time, UTC-08:00)
Hi Marcus;

There are three approaches:

1) Make a PowerShell equivalent of vcvarsall.bat
2) Use the script given above to run vcvarsall.bat
3) Start vcvarsall.bat, and then type 'powershell' to start a PowerShell prompt from within.

Lee
Thursday, August 16, 2007 8:47:37 PM (Pacific Daylight Time, UTC-07:00)
I just made this from C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat, and works for me.

$env:VSINSTALLDIR = "C:\Program Files\Microsoft Visual Studio 8"
$env:VCINSTALLDIR = "C:\Program Files\Microsoft Visual Studio 8\VC"
$env:FrameworkDir = "C:\WINDOWS\Microsoft.NET\Framework"
$env:FrameworkVersion = "v2.0.50727"
$env:FrameworkSDKDir = "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0"

write-output "Setting environment for using Microsoft Visual Studio 2005 x86 tools."

$env:DevEnvDir = "C:\Program Files\Microsoft Visual Studio 8\Common7\IDE"

$env:PATH = "C:\Program Files\Microsoft Visual Studio 8\Common7\IDE;C:\Program Files\Microsoft Visual Studio 8\VC\BIN;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\bin;C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\bin;C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 8\VC\VCPackages;" + $env:path
$env:INCLUDE = "C:\Program Files\Microsoft Visual Studio 8\VC\ATLMFC\INCLUDE;C:\Program Files\Microsoft Visual Studio 8\VC\INCLUDE;C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include;C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\include;" + $env:INCLUDE
$env:LIB = "C:\Program Files\Microsoft Visual Studio 8\VC\ATLMFC\LIB;C:\Program Files\Microsoft Visual Studio 8\VC\LIB;C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\lib;C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\lib;" + $env:LIB
$env:LIBPATH = "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 8\VC\ATLMFC\LIB"


yoshi
Name
E-mail
Home page

Comment (Some html is allowed: b, blockquote@cite, em, i, strike, strong, sub, super, u)  

Enter the code shown (prevents robots):