App-V and Legacy NTFS Junctions

Written by packageologist. Posted in App-V v4.x, App-V v5.x

I was having problems recently sequencing an application named SolarWinds Toolset; it appeared to be ignoring the data stored under C:\ProgramData captured during sequencing and instead reading/writing files to this location outside of the virtual environment.

A bit of Procmon analysis showed that the application was trying to read from C:\ProgramData\Application Data. On Windows Vista and 7, this is not an actual folder but an NTFS junction; a reparse point so that (badly written) legacy apps designed for Windows XP can be redirected to write to the correct location. NTFS junctions are similar to file/folder shortcuts that you may see on your desktop, but they are put in place all over Windows 7 to aid application compatibility after Microsoft changed the folder structure since Vista. You can easily view just how many of these there are on your system by running the following command:

dir /s /al c:\

Applications are supposed to query Windows APIs to determine exactly where the per-user and per-machine app data locations are. But often developers use alternate methods, such as %ALLUSERSPROFILE%\Application Data and %USERPROFILE%\Application Data. On XP these folders would equate to C:\Documents and Settings\All Users\Application Data and C:\Documents and Settings\USERNAME\Application Data. After changing the folder structure since Vista, NTFS junctions are used to redirect attempt to write to these location to the correct place.

For example, say an application tries to write to: %ALLUSERSPROFILE%\Application Data on Windows 7, which actually would prefer you to store per-machine appdata to C:\ProgramData. To achieve this, %ALLUSERSPROFILE% is set to C:\ProgramData, and in there is an NTFS junction shortcut Application Data, which also points to C:\ProgramData. All of this redirection goes on transparently behind the scenes and it all works wonderfully.

Except if you try to run this application inside App-V!

You can try the following test for yourself on either App-V 4 or 5. Here is a simple batch file that tries to read and write to these junction points:

@echo off

echo Program data:
type "%ALLUSERSPROFILE%\Application Data\Test\config.txt"

echo User data:
type "%USERPROFILE%\Application Data\Test\config.txt"

echo.
echo Updating data files...
echo.

IF NOT EXIST "%ALLUSERSPROFILE%\Application Data\Test\config.txt" (
md "%ALLUSERSPROFILE%\Application Data\Test"
echo This file stores program data >"%ALLUSERSPROFILE%\Application Data\Test\config.txt" )

IF NOT EXIST "%USERPROFILE%\Application Data\Test\config.txt" (
md "%USERPROFILE%\Application Data\Test"
echo This file stores user data >"%USERPROFILE%\Application Data\Test\config.txt" )

echo Program data:
type "%ALLUSERSPROFILE%\Application Data\Test\config.txt"

echo User data:
type "%USERPROFILE%\Application Data\Test\config.txt"

pause

This simply does the following:

  1. Tries to read 2 config files using the %ALLUSERSPROFILE%\Application Data and %USERPROFILE%\Application Data locations.
  2. If they do not exist they are created.
  3. Then it tries to read the config files again.

This mimics simple application behaviour where it will try to read its config files and create default ones if none exist.  Running this locally, we see this on the first run as expected:

firstrun

Then on each successive run the script can find the files both times:

secondrun

Now, you can sequence this batch file and create a shortcut to it.  On App-V 5, you will also have to craft your shortcut to run cmd.exe /c <path to batch file>, since shortcuts directly to batch files run outside of the virtual environment by default (see here for a previous post detailing this).  You can launch the app as many times as you like during sequencing and the same result as above will be displayed.  However, on first launch on the App-V client, the result from the first window will be displayed; the script cannot find the files in the requested location.  It then creates them and can read them again, but it appears that this redirection has pointed to the folders outside of the virtual environment and the files are created on the local file system instead.

I believe the reason for this is as follows. App-V only virtualises subfolders under the common VFS folders that are created or written to during sequencing. So if your app creates %APPDATA%\Test during sequencing, it will be captured and virtualised, and all reads and writes to this location will be redirected to the user’s PKG file in App-V 4, or the user locations under their profile in App-V 5. However, if in later use on the client the application tries to create a folder %APPDATA%\Test2, App-V will allow these file operations to take place on the local file system since that folder was not captured during sequencing. Since the subfolder Application Data was not captured during sequencing as the location does not really exist, App-V does not attempt to virtualise or redirect access to this location.

Hopefully this will not affect too many applications since most should be using the ‘proper’ methods for determing the folder locations.  But the potential undesired impacts of this are:

  • If you configure an application during sequencing, it may not be able to find the configuration on client launch.  This could either cause the application to crash, or for it to recreate default settings files.
  • If you have two conflicting applications, such as two different version of the same product, they could both be trying to write to the same location with unintended results.
  • For multi-user systems or terminal servers, one user can change the application configuration which will also affect other users.

I have found a workaround  for this problem, which could help resolve these issues if they are affecting you.  On your sequencer, before monitoring, delete any of the affected NTFS junctions (you will need to enable the viewing of hidden and system files in Explorer) and recreate them as real folders.  Then in the example above, the sequence would actually capture the folder C:\Programdata\Application Data\Test, and this would then read and write correctly on the client.

This fix didn’t work for the application I was working on originally since it contained many components, some of which use the proper methods for determining the folder locations, and some which didn’t – resulting in the data being split across two locations, which it did not like.  Microsoft’s Application Compatibility Toolkit may be a solution in these dire cases where you need to force the application to redirect to an alternate location!

Launching reg / bat / cmd / vbs files in App-V 5

Written by packageologist. Posted in App-V v5.x

App-V 5 behaves a little differently to App-V 4 when it comes to launching files with different file extensions.  For instance, if you have a shortcut pointing to a PDF file, in App-V 4 this could prove a problem if Adobe Reader was already running since it would pass the command onto the already running instance asking it to open a file in the virtual environment that it could not see.  This is no longer a problem in App-V 5 since the shortcut points directly to a PDF file under C:\ProgramData which Adobe can open since the location is always visible.

I had the pleasure of sequencing an application recently that had start menu shortcuts to .reg files to configure the application in different ways.  When launching these .reg files, the registry settings were applied locally, outside of the virtual environment, which were then hidden from the application due to the main keys being set to override.  The solution to this was to point the shortcuts to C:\Windows\Regedit.exe <Path to reg file> instead.  But then I had to do a couple of tests to satisfy my curiosity to see what would happen with batch files and vbscripts!

I created a .bat, .cmd and .vbs file that each created a registry key under HKCU and added them to a sequence.  A point of note is that the vbscript uses the RegRead method, since the WMI method will always write outside of the bubble anyway due to the WMI Windows service being run outside of App-V.

Test.bat:

reg add HKCU\Software\Test /v Test.bat /d Success /f

Test.cmd:

reg add HKCU\Software\Test /v Test.cmd /d Success /f

Test.vbs:

Set wshShell = CreateObject("WScript.Shell")
wshShell.RegWrite "HKCU\Software\Test\Test.vbs", "Success", "REG_SZ"

The result was that the .bat and .cmd wrote the registry keys outside of the virtual environment, whereas the .vbs file wrote the registry entry inside the virtual environment as desired.

To workaround this you can change the shortcut to run cmd.exe /c <Path to batch file>.  I don’t know why .vbs behaves differently and we don’t have to resort to using wscript.exe <Path to script file>, but nobody ever said that any of this would make any sense!

Fix for MSI packages created with App-V 5.0 SP1

Written by packageologist. Posted in App-V v5.x

So, having just started a project where I get to use App-V 5 outside of the lab environment, this of many posts I plan to make regarding v5, hopefully some of you may find it useful!

The MSI packages created by the 5.0 SP1 sequencer refuse to install on the client, showing the following in the MSI log:

Error: could not load custom action class Microsoft.AppV.MsiTemplate.CustomActions.CustomActions from assembly: AppVMsiPackageTemplate

Using InstEd, I generated a transform between a 5.0 and similar 5.0 SP1 package. I then stripped out all of the application-specific entries to be left with just a couple of changes to the binary table. These hold the custom action dlls responsible for the error above.

To use this, just append the following to your msiexec command line:

msiexec /i package.msi /qb TRANSFORMS=AppV5_MSI_Fix.mst

Using InstEd/Orca or similar, you can also save a transformed version if you don’t want to mess about with command lines.

Use this at your own risk! Whilst everything appears to work fine so far, this is unsupported by Microsoft. I suspect that all the dlls are doing is running Powershell commands to import the package, and as far as I know these haven’t changed, so you should be ok.

Click here to download the MST.

 

UPDATE:

Sebastian Gernert, App-V issue escalation engineer at Microsoft, has posted an alternative solution on his blog which involves adding a couple of registry keys to the client:

http://blogs.msdn.com/b/sgern/archive/2013/05/23/10420879.aspx

Or if you don’t speak German:

http://kirxblog.wordpress.com/2013/05/24/if-app-v-5-msis-arent-working

App-V v4.6 Virtual Registry Bug

Written by packageologist. Posted in App-V v4.x

I came across a strange issue today whilst sequencing Oracle Developer Suite 10g.  Sequencing appeared to work at first but some of the shortcuts were not working correctly.  Upon opening regedit in the bubble to troubleshoot I found that most of my registry settings had disappeared!  Here is what the registry was supposed to look like:

Real Registry

And here is what I saw from inside the virtual environment:

Virtual Registry

It appeared that the App-V client had helpfully thrown out all of my settings and subkeys except for one suspicious key with a path to a user variable, sitting in the HKLM registry.  Thanks!

Whilst no developer in their right mind would normally store user specific settings under HKLM, this is Oracle we are talking about here, so common sense does not apply.

I experimented by removing this REPORTS_TMP key in the sequencer, and all of the missing values came back!  If I put any user specific variables in, the same would happen, %CSIDL_APPDATA%, %CSIDL_DESKTOPDIRECTORY%, etc – but variables such as %CSIDL_PROGRAM_FILES% worked fine.

So, this is weird, but I had a workaround – delete the problematic key in the sequencer and add <REGISTRY> tags in the OSD files to bring the setting back.  But I did a quick test on my own environment, fully patched to v4.6 SP2 Hotfix 1 to see if I could replicate it.  I created a new sequence containing just the following registry keys:

[HKEY_LOCAL_MACHINE\Software\Wow6432Node\TEST32]
"Normal String 1"="Hello"
"Normal String 2"="World!"
"User Folder 1"="C:\\Users\\testadmin\\AppData\\Local\\Temp"
"User Folder 2"="C:\\Users\\testadmin\\AppData\\Roaming"

[HKEY_LOCAL_MACHINE\Software\TEST64]
"Normal String 1"="Hello"
"Normal String 2"="World!"
"User Folder 1"="C:\\Users\\testadmin\\AppData\\Local\\Temp"
"User Folder 2"="C:\\Users\\testadmin\\AppData\\Roaming"

[HKEY_CURRENT_USER\Software\TEST]
"Normal String 1"="Hello"
"Normal String 2"="World!"
"User Folder 1"="C:\\Users\\testadmin\\AppData\\Local\\Temp"
"User Folder 2"="C:\\Users\\testadmin\\AppData\\Roaming"

And also a couple of desktop shortcuts pointing to %CSIDL_SYSTEM%\regedt32.exe (32-bit regedit) and %SFT_SYSTEM32_X64%\regedt32.exe (64-bit regedit) to help troubleshoot.  Here are the keys in the sequencer:

Sequencer

After importing into the client, the HKCU registry settings are displaying properly:

HKCU Results

But both 32-bit and 64-bit portions of the HKLM keys were only displaying the keys containing user-related variables:

Test32 Results

Test64 Results

So, bear this in mind – if you’re troubleshooting and are not seeing much in the HKLM registry except for some user directories, look for this.  Delete the keys from the sequence and add them either by <REGISTRY> tags if you don’t mind them being reset on each launch, or by using a pre-launch script if you think that the users may wish to change the values themselves when using the application.