I recently had the need to leverage a Softgrid pre-launch script to copy an INI file into a subfolder of the user’s Application Data folder. Softgrid has two methods of pre-launch scripting:
- HREF
- SCRIPTBODY
There’s a full description of the difference between HREF and SCRIPTBODY by Sean Donahue over here on the App-V Team blog. But as a quick reference point, HREF tags do not allow commands like mkdir/md, etc. In my case, I need to create a directory if it doesn’t exist and then copy the INI file up to it. While I certainly could create a BAT/CMD script and reference it from an HREF tag, I wanted to embed the entire script within a scriptbody tag so it’s self documenting and maintainable outside of hard coded references to a network location or some CMD/BAT within the virtual environment.
Let’s start with what my pre-launch script needed to do:
1) Check to see if the app’s ini file already existed at the desired location. No reason to copy it if it’s already there.
2) Assuming the file wasn’t there, I need to create a folder to house the INI file.
3) Finally I need to copy the INI file from a location inside the virtual app package. This could have easily been from a network location as well.
Ignoring Softgrid, my batch file to do this would look something like this:
@echo off
if exist "%appdata%\SomeApp\Prod\app.ini" goto SkipProdINI
md "%appdata%\SomeApp\Prod"
xcopy "Q:\App8.3\inifiles\app.ini" "%appdata%\SomeApp\Prod" /y>nul
:SkipProdINI
However, SCRIPTBODY tags have two interesting properties:
1) Each line must be terminated by “\n”
2) Backslashes must be escaped (i.e. in order to get a backslash in the script execution, you must use double backslash \\. So for a UNC path, it might look like this \\\\server\\share\\somefile.ini)
So to rewrite my script in a scriptbody tag, it would need to look something like this:
@echo off\n
if exist "%appdata%\\SomeApp\\Prod\\app.ini" goto SkipProdINI\n
md "%appdata%\\SomeApp\\Prod"\n
xcopy "%SFT_MNT%\\App8.3\\inifiles\\app.ini" "%appdata%\\SomeApp\\Prod" /y>nul\n
:SkipProdINI\n
However, there’s a problem with this. The issue is that %APPDATA% is a runtime expanded string. Meaning when the script is run, the value of the APPDATA environment variable is expanded inline. However, Windows knows nothing about the Softgrid client’s need for escaped backslashes. So what you end up with is an invalid directory path since the single backslashes contained within the expanded APPDATA variable are not converted properly.
What should we do about this issue?
There’s really only two options to resolve this issue:
1) Put everything into a .CMD or .BAT file and call it using an HREF tag instead of a SCRIPTBODY.
2) Find some way to escape the backslashes in the environment variable.
I chose number 2 because it’s more interesting
The solution:
The DOS SET command has a capability that few people know about — character substitution
What I need to do to resolve my issue is replace any single backslashes with a double backslash. The character substitution available in the SET command will do this exact thing. So what I did was to create a new environment variable on the fly named APPDATAESC (the esc stands for escaped in this case). APPDATAESC contains the contents of APPDATA, but uses character substitution to replace the single backslashes with double backslashes. The actual command looks like this:
set APPDATAESC=%APPDATA:\=\\%\n
When this line executes, the contents of the APPDATA environment variable are read in, any single backslash character is traded for a double backslash and then the final contents are assigned to APPDATAESC. Then I can use the environment variable APPDATAESC throughout my script to refer the the APPDATA location and it’s safely escaped. Here’s an example of the completed script:
@echo off\n
set APPDATAESC=%APPDATA:\=\\%\n
if exist "%appdataesc%\\SomeApp\\Prod\\app.ini" goto SkipProdINI\n
md "%appdataesc%\\SomeApp\\Prod"\n
xcopy "%SFT_MNT%\\App8.3\\inifiles\\app.ini" "%appdataesc%\\SomeApp\\Prod" /y>nul\n
:SkipProdINI\n
Hopefully this helps someone in a similar sitation.
Agree? Disagree? Let me know with a comment...