Get Powershell and Command Script (Batch) files to play nice together


I needed a script that could perform SVN operations, kick off a legacy command script (.bat) and perform other mundane tasks. As this was on a Windows system I used my PowerShell experience to put together a script that tied everything together.

Up until now I have had minimal trouble kicking off command scripts- but for some reason PowerShell would not execute this one script. It just barfed and threw this error:

PS C:\SVN\SourceCode> Invoke-Expression "cmd /C `"cd $SourceDir & .\Projs\ParentBuilder.cmd`""
Setting environment for using Microsoft Visual Studio 2010 x86 tools.

Building with the Configuration set to Debug.
cmd.exe : 'KickOffBuild.cmd' is not recognized as an internal or external command,
At line:1 char:4
+ cmd <<<<  /C "cd C:\SVN\SourceCode & .\Projs\ParentBuilder.cmd"
    + CategoryInfo          : NotSpecified: ('KickOffBuild.cmd'...ternal command,:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

operable program or batch file.

Notes

 

 

Background

The legacy batch script is one of the build scripts left over from our old system (Our Configuration Management (CM) lead is putting together a new system that moves away from batch scripts). The hang-up appears to be a call command in the script which kicks off another script in the same directory.

As the script works fine when executed from a regular dos prompt it seemed logical to use this command to kick off the batch script:

Invoke-Expression "cmd /C `"cd $SourceDir & .\path\to\command.bat"

Note: cmd /C launches a new instance of cmd.exe which executes the command specified after /C then terminates the session


Unfortunately this command did not work- I still can't explain why. Since it is running in a natvie cmd.exe process everything should work the same as if I had run the command from the shell prompt manually.

 

Troubleshooting

I ran some tests which used fresh batch scripts that used the call command to kick off other scripts and found that I could duplicate the XXXX is not recognized as an internal or extranl command if the scripts were not in the %PATH% variable or if an absolute path to the script was not specified.

After a bit more finangling I realized that the dot . character does not mean 'current directory' in a batch script like it does in BASH. A few dozen google searches later and I found out that the 'right here' token in command script is the easy to remember %~dp0

I had to pre-pend %~dp0 to the call command and a few other Environment variables that were being set in the calling script. Here are a the affected lines of the script:

Before:

set ROOT=..\myProjectsDir
set BUILD=Debug
set PAUSEWITHCRITERIA=false
set OUTDIR=..\output\Admin
set OUTSDKDIR=..\output\SDK
set OUTSERVERDIR=..\output\server
set OUTMANAGEMENTDIR=..\output\management

call %~dp0KickOffBuild.cmd
 

After:

set ROOT=%~dp0..\myProjectsDir
set BUILD=Debug
set PAUSEWITHCRITERIA=false
set OUTDIR=%~dp0..\output\Admin
set OUTSDKDIR=%~dp0..\output\SDK
set OUTSERVERDIR=%~dp0..\output\server
set OUTMANAGEMENTDIR=%~dp0..\output\management

call %~dp0KickOffBuild.cmd


Note 1:
 There shoud NOT be a backslash following %~dp0 as this causes errors (from my limited experience working with the token)

Note 2: A keen eye will note that there is relative pathing that happens after I specify the 'This directory' token. If I had taken more time I could have placed a better token in place to eliminate the need to back-up a directory. As this is a legacy script that will be replaced sometime in the next few months I settled on the more direct fix. 


Summary: Watch out for relative pathing and environment variables when calling complex legacy scripts from PowerShell.