Thursday, April 16, 2015

Writing windows .bat files for cmd.exe: cheatsheet

Here's a cheatsheet of some things I've discovered when writing a .bat script to build things.

For comments you can use "rem" i.e. remark but "::" is nicer IMHO:
rem This is a comment
:: This is too
To set environment variables: (Note that ALLUSERSPROFILE will only get expanded once, so if it changes this will break)
:: Permanently in HKLM which will persist for all shell sessions:
SETX /M PATH "%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"

:: or temporarily, just for this one
SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
A few warning notes here. %PATH% expands to the combination of user and system paths, i.e. the contents of both of these keys:
HKEY_CURRENT_USER\Environment
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\Environment
This means that if you're doing a setx as above and there is stuff in HKCU then you are duplicating it in the path every time. This is a problem because of the 1024 character limit on %PATH%. So you may want to clear out the HKCU path:
SETX PATH ""
Download a file with powershell:
powershell -NoProfile -ExecutionPolicy unrestricted -Command "(new-object System.Net.WebClient).DownloadFile('https://downloads.activestate.com/ActivePerl/releases/5.20.2.2001/ActivePerl-5.20.2.2001-MSWin32-x86-64int-298913.msi', 'ActivePerl-5.20.2.2001-MSWin32-x86-64int-298913.msi')"
There seems to be no actual equivalent of the bash "set -e", i.e. exit if any command returns an error, but you can do it per command like this, where the number is the error code:
choco install git -y || echo "git install failed" && exit /b 1
Recursively delete a directory, with no prompting:
rd /s /q openssl-1.0.2a
Get a visual studio environment for building:
:: 64 bit
call "%PROGRAMFILES% (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64\vcvars64.bat"

::32 bit
call "%PROGRAMFILES% (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat"
Copy a whole directory recursively. Create the destination directory if necessary:
xcopy C:\Build-OpenSSL-VC-64\include C:\pkg\include\ /s /e /h /y
Calling other .bat files

You basically have two options, either create a completely new process (so changes made to environment variables, CWD etc. will not affect the parent):
cmd /c "mybat.bat"
Or use call, which is effectively like inlining all the commands from that .bat file:
call mybat.bat
Note that if you don't use call, some_other_command in this example will never get executed since you're essentially saying "replace everything from here on with the contents of mybat.bat":
mybat.bat
some_other_command
Mounting a shared folder

This will mount a virtualbox shared folder, clearing any existing drive mapped to X:
net use x: /delete
net use x: /persistent:no \\VBOXSVR\host
x:

No comments: