Fix system junction points (symbolic links) with alternate profiles directory.

For numerous reasons, I needed to define an alternate local users directory on my Server 2008 and Windows 7 installations, my plan was to rename the directory "users" to "profiles". I have detailed the method to do that automatically: Installing Server 2008 (and R2) with alternate Profiles (Users) directory using unattended method. I have also detailed a manual method on the Manually move Server 2008 Profiles (Users) directory page.

NOTE: Although I first wrote this for Windows 2008, I can confirm that this information also applies to Windows 7 Professional. It would seem Server 2008 R2 and Windows 7 have identical profile setup, directory structure, and functionality.

After a system is running with an alternate local profiles directory, There are known issues with system directory junction points documented in Microsoft KB article 929831. To fix this problem, I created a batch file script (below) to fix all problem junction points.

Background:
What strikes me as astounding is that a fresh 2008 Server install using the ProfilesDirectory parameter in autounattend.xml does NOT correctly create the junction points using this variable! Considering I am NOT a batch file expert, I would think if I could fix the junction points with a batch file, it seems insufficient that Microsoft's install process does not correctly create the junction points.

Quick primer for those unfamiliar with junction points: think of a program that insists on saving some information to the 'C:\Documents and Settings\All Users' directory, but that directory no longer exists under Windows 2008/Vista/7. So that would be nice if we could make an 'alias' or 'shortcut' redirecting the 'C:\Documents and Settings' directory to the 'C:\Profiles' (or by default 'C:\Users') directory. For those familiar with *nix systems, these are known as symbolic links.

Additionally, in the process of recreating the junction points, I discovered there was an endless loop in the directory structure created, in that there is at least one known instance of a link pointing to a parent directory. When a program such as a backup program descends through the directory tree, the junction point is encountered, and listing it's (aliased to parent directory) contents lists again the junction point, which again lists the parent directory, creating an endless loop. Just do an internet search for "Application Data\Application Data\Application Data" and you will see numerous references to this problem.

Microsoft's solution to this problem is to add a 'deny list directory for everyone' permission to the junction point. It is annoying that in Windows Explorer, you double-click a junction point and you get 'Access Denied' message, but this is actually necessary to prevent recursive loops. Note that just 'List Directory' permission is denied, but all other read and write permissions are in effect allowing hard-coded paths to 'C:\Documents and Settings' to function correctly.

In my batch file, you will see that I was able to use a couple of 'icacls' commands to duplicate the Microsoft default permissions, and then change the attributes on the junction point with the 'attrib' command to duplicate the Microsoft attributes. Warning: be careful to apply to these commands with the '/L' switch, so that the command executes against the junction point (symbolic link), OTHERWISE the command will execute on the directory pointed to!

See for yourself
In Windows Explorer, (with 'show hidden and system files' enabled) junction points will *usually* appear as a folder with a shortcut arrow on it. From the command prompt, junction points are hidden when listing files. To view the junction point information for 'C:\Documents and Settings' at the command prompt,
change to the root directory: cd \
then use the list files with 'Link' attribute: dir /al C:\
you should see: 07/18/2010  06:35 PM    <JUNCTION>      Documents and Settings [C:\Users]

This indicates that 'C:\Documents and Settings' is redirecting to the 'C:\Users' directory. You can list all junction points on the entire C: drive by adding the 'recurse sub-directories' switch:
dir /al /s C:\

Be aware that this list will be a bit large. Before you use the script to fix the links, you should probably run this command with output redirected to a reference file so that you have a snapshot of your system before any changes were made.

Preview script
You can copy & paste a script that will preview the changes: TweakSymbolicLinksPreview.txt. You may want to compare the output to the reference file created in the previous paragraph, only links that contain the path in the FindBadDir variable will be listed.
Example: C:\TweakSymbolicLinksPreview.bat > C:\OrigSymbolicLinks.txt

DISCLAIMER: Using this script, or any of this advice may turn your system into a puddle of silicon or cause a complete loss of all data. Use at your own risk! Perhaps it was an accident that this worked for me. This information is intended for IT administrators, if you are unsure of any of these terms then you should probably get some expert advice.

Of course, you can tweak this batch file to suit your needs. I saved both the TweakSymbolicLinksPreview.bat file and the TweakSymLinks.bat batch file to the root of the C: drive, and cd'd to the root directory in Command Prompt to execute the batch file.

TweakSymLinks.bat script

-----------------------------------------------------------------------------------------
:: Sample TweakSymLinks.bat file
:: DISCLAIMER: Using this script, or any of this advice may turn your system into a puddle
::             of silicon or cause a complete loss of all data.  Use at your own risk!
:: Author: Jay Ohman, Ohman Automation Corp.
:: Rev: 10/30/2011
:: Purpose: Script for changing all junction points and symbolic links when referenced path
::          has changed.
:: Development Reference: (contains debug echo's and fully commented)
::              http://www.OhmanCorp.com/RefWin-Win2008R2-TweakSymbolicLinksPreview.txt

@echo off
setlocal

echo ----------------------------- BEGIN -----------------------------
C:
set FindBadDir=C:\Users
set CorrectDir=C:\Profiles
:: ** if desired, try a simpler directory first
set BeginDir="\"
:: set BeginDir="\Profiles"
:: set BeginDir="\Profiles\Default\Documents"

cd %BeginDir%
echo Fetching all junction/symlink references from entire C: drive....
for /f "tokens=1-3 delims=><" %%a in ('dir /al /s') do call :x1 "%%a" "%%b" "%%c"
goto :finish

:x1
  echo %~1 | findstr /i /r /c:"Directory of C:" > NUL && call :x2 %1
  echo %~3 | findstr /i /r /c:"%FindBadDir:\=\\%" > NUL && call :x3 %3
goto :EOF

:x2
  set xLin=%~1
  set xCurDir=%xLin: Directory of C:=C:%
  if NOT "%xCurDir%"=="C:\" set xCurDir=%xCurDir%\
  echo Checking directory: %xCurDir%
goto :EOF

:x3
  set xLin=%~1
  set xParseLin=%xLin:     =%
  for /f "tokens=1-2 delims=][" %%i in ('echo %xParseLin%') do call :x4 "%%i" "%%j"
  set xLin=
  set xParseLin=
goto :EOF

:x4
  set xTmp=%~1###
  set xFPName=%xCurDir%%xTmp: ###=%
  set xFPDestBad=%~2
  Setlocal EnableDelayedExpansion
  set xFPDestNew=!xFPDestBad:%FindBadDir%=%CorrectDir%!
  Endlocal&Set xFPDestNew=%xFPDestNew%
  echo ----------------------------------------------------------
  echo   Old: %xFPName% --^> %xFPDestBad%
  echo   New: %xFPName% --^> %xFPDestNew%
  echo Deleting old Junction: %xFPName%
  rmdir "%xFPName%"
  echo Making new Junction:
  mklink /J "%xFPName%" "%xFPDestNew%"
  echo Changing permissions:
  icacls "%xFPName%" /deny everyone:(RD) /L
  icacls "%xFPName%" /setowner SYSTEM /L
  echo Changing attributes:
  attrib +S +H +I "%xFPName%" /L
  rem pause

  set xTmp=
  set xFPName=
  set xFPDestBad=
  set xFPDestNew=
goto :EOF

:finish
set FindBadDir=
set CorrectDir=
set BeginDir=

:: -- remove these next lines if you prefer the *spoofed* names to appear
del /ah "C:\Profiles\desktop.ini"
del /ah "C:\Profiles\Public\Documents\desktop.ini"
del /ah "C:\Profiles\Public\Downloads\desktop.ini"
del /ah "C:\Profiles\Public\Music\desktop.ini"
del /ah "C:\Profiles\Public\Pictures\desktop.ini"
del /ah "C:\Profiles\Public\Videos\desktop.ini"

echo ------------------------------ END ------------------------------
-----------------------------------------------------------------------------------------

If you want to verify the batch file worked, use the Command Prompt to again list the Link files at the root directory: dir /al C:\
you should see: 07/18/2010  06:35 PM    <JUNCTION>      Documents and Settings [C:\Profiles]
(or whatever alternate name you chose).

NOTE: you will see at the end of the batch file some commands to delete some desktop.ini files. For some *unfathomable* reason, Microsoft decided that in Windows Explorer, the 'Public\Music' directory should appear as 'Public\Public Music'. Then to *really* make an admin see red, the desktop.ini created from the autounattend.xml install in the 'C:\Profiles' directory will make the folder appear as '\Users'! Now why-in-the-world would it be desirable to have a *spoofed* directory name on a server?! I absolutely detest spoofed directory names! (I have yet to see any benefit what-so-ever to having desktop.ini files on a server, I should just delete them all). *end of rant*

Should you decide to move the location of the "Documents" directory (formerly known as "My Documents"), say to another local drive or network drive, you may want to recreate the links in the "Documents" directory to the new location. Tip: changing the location of "My Documents" was fairly easy in Windows XP, to do this in Win7/2008R2 is a little more complicated, navigate to: "Libraries\Documents\My Documents" and right-click My Documents choose "Properties". In the pop-up window, you should now see the familiar "Location" tab that you can use to move the location of the "Documents" folder. You will need to repeat this process under "Libraries" for Music, Pictures, and Videos.

I believe Microsoft created these symbolic links in case any programs are expecting "My Pictures" to be located under the directory "My Documents" as was the case in Windows XP. Note that Music, Pictures, and Videos directories are no longer located under "Documents" (My Documents). Instead these directories are now "Moved up a level" to the user's profile (root) directory.

One more tip: if you decide to also move the "Public" directories to another location, you may need to re-create the desktop.ini files to restore the original appearance of these directory names. There is a good reference for re-creating desktop.ini files by Windows7Themes.Net at: Desktop.ini in Windows 7.

Feel free to send me feedback if you find any mistakes, or if this saved you a bunch of time.



Copyright 1996-2017 Ohman Automation Corp. All rights reserved.