App-V 5, Junctions and Path Length Limitations

I was migrating an old application recently which launched Macromedia Director.  It launched fine during sequencing and when installed locally, but when I ran the App-V 5 version i saw the error message:

Unable to load movie playlist. Does the .INI file exist? It must contain a section ‘[Movies]’ with an entry ‘Movie01=Pathname.dir’.

To cut a story short, it turns out the when App-V mounts the application to a path such as C:\ProgramData\App-V\[PackageGUID]\[VersionGUID]\Root\Vocal Pathology_1\Vocal Pathology_I.exe  the path name becomes too long and exceeds the character limit of 127 characters!  See here.

The only way I could think of resolving this via an App-V package would be to spoof it by using a symbolic link, or more specifically a ‘junction’.

Both symbolic links and junctions essentially link one location to another location.  But creating a junction seemed like a better option according to this post on SuperUser – I particularly liked the way that remote users could access the junction from a remote computer.

Our task then, was to create a short path junction that would link to the longer path used by App-V.

When creating a junction on the command line, the syntax is:

mklink /J "[Non Existing Junction Full Path]" "[Existing App-V Full Path]"

It’s important to note that where you are linking from should NOT exist when you run this command, and where you are linking to SHOULD exist. 

We will create a junction with the path of C:\VocalPathology after the package is added (hence at publish time) so that the target path exists, and for cleanliness we will also remove the junction at the time of un-publishing the app.

In the UserConfig.xml file (my apps are published to users and not machines) I added the following code – note that I first rename C:\VocalPathology if it already exists (otherwise creating a junction will fail), then create the junction.  Also note that the token [{AppVPackageRoot}] ultimately resolves to C:\ProgramData\App-V\[PackageGUID]\[VersionGUID]\Root and that our target executable lives in a sub folder of the package root called ‘Vocal Pathology_1’.
.

<UserScripts>
	<PublishPackage>
		<Path>cmd.exe</Path>
		<Arguments>/c move /Y "C:\VocalPathology" "C:\VocalPathology.old" &amp; mklink /J "C:\VocalPathology\" "[{AppVPackageRoot}]\Vocal Pathology_1\"</Arguments>
		<Wait RollbackOnError="false" Timeout="30"/>  		
	</PublishPackage> 		
	<UnpublishPackage>
		<Path>cmd.exe</Path>
		<Arguments>/c rmdir "C:\VocalPathology\"</Arguments> 
		<Wait RollbackOnError="false" Timeout="30"/>  		
	</UnpublishPackage>
</UserScripts>

Now that we have created the junction, we need to amend where the shortcut points to in our UserConfig file! Find the <Shortcuts> section and amend the <Target> element.  Beforehand it points to the the full App-V location since it uses [{AppVPackageRoot}]:

<Target>[{AppVPackageRoot}]\Vocal Pathology_1\Vocal Pathology_I.exe</Target>

But we will need to hard-code the shortcut to point to our junction (shorter path) instead. The new shortcut will be:

<Target>C:\VocalPathology\Vocal Pathology_I.exe</Target>

When the package gets published, the shortcut will get ‘sucked’ into the virtual file system since App-V will append the /appvve parameter like so:

"C:\VocalPathology\Vocal Pathology_I.exe" /appvve:[PackageGUID]_[VersionGUID]

 

Create a Symbolic Link from a Custom Action

Creating a symbolic link can be achieved using the MKLINK internal command.  Internal commands are native to the windows command shell and are NOT executable files.  As such, we must call these commands via the windows command shell as follows:

Let’s pretend we have a physical folder in C:\Program Files\AlkaneSolutions but we want to create a symbolic link to it in the root of C:\ called ‘AlkaneSolutions’.  I would use the following MKLINK command:

MKlink /D C:\AlkaneSolutions "C:\Program Files\AlkaneSolutions"

From a custom action we should do 2 things:

1.  We cannot call MKLINK directly since it’s an internal command and not an executable.  So instead we call CMD.exe with the /c parameter (/c runs the command and then terminates the command prompt) and then pass the MKLINK command afterwards.

2.  We should not include any hardcoded paths, and instead try to use windows installer properties where possible.  Remembering to enclose any paths in quotes!

As such, and when scheduling the Custom Action to run in a deferred context just before InstallFinalize, our Custom Action should look similar to this:

MKLINK commandThe action ‘MKLINK’ is merely the name of our Custom Action.  The Type relates to the type of custom action and its execution options.  The Source of [SystemFolder] relates to the location of CMD.exe.  And the Target is the command we want to run.