I'm betting you, and your users, spend of lot of time in Windows 7 using Windows Explorer to navigate the file system. If by chance you've enabled Explorer to show hidden and system folders, you might see something like Figure 1.


Figure 1 Hidden and System Folders

If you try to access something like Application Data, you end up with an error.


Figure 2 Access Error

To understand why you have to look under the hood, via the command prompt.


Figure 3 Looking at Hidden Folders

C:\Users\jeff> dir /ahd

Application Data is something called a junction. Figure 4 shows a different type of beast in this menagerie.


Figure 4 A Symbolic Link

You won't see a similar result for this particular folder on your computer. This is something I added. But why and what is it? In this article I want to explore the world of reparse points, junctions and symbolic links in Windows 7. We'll look at ways to identify these file system creatures as well as creating and deleting our own. Let's begin with a few definitions.

A reparse point is a special NTFS feature that Windows uses to identify and manage mount points for drives and junction links for directories. Think of a mount point as the place where Windows connects physical volumes to logical entries such as drives and folders. A symbolic link is any link that redirects the file system from one location to another. A junction point is a symbolic link typically used for folders. Think along the lines of virtualization. You think you are accessing C:\Work but you are really being directed to E:\files\data\work. Lastly there is something called a hardlink. This is the NTFS directory entry for everything in the file system. Files all have at least one hardlink but you can add more. We'll look at that later.

The first step is identifying and finding all of these NTFS critters. Identifying mount points is perhaps the easiest using the mountvol.exe command line tool.

C:\> mountvol

If you run the command without any parameters you'll get help and a list of all current mount points.


Figure 5 Mounted Volumes

As you can see in Figure 5, in addition to the drive mount points, I have a volume mounted in the folder c:\work\vhd. If I look at the directory structure from the command prompt I can see that this is a junction.

C:\Users\jeff>dir c:\work /ad
 Volume in drive C has no label.
 Volume Serial Number is A4BA-3EFF

 Directory of c:\work

01/20/2012' 05:00 PM''' ''''''''' .
01/20/2012' 05:00 PM''' ''''''''' ..
09/14/2010' 02:33 PM''' ''''''''' reports
01/20/2012' 05:00 PM''' '''' vhd [\??\Volume{2dd97d8a-3bab-11e1-'
'''''''''''''' 0 File(s)''''''''''''' 0 bytes
'''''''''''''' 4 Dir(s)'' 9,051,111,424 bytes free

This is where the terminology gets a little confusing. I have a mount point at C:\Work\vhd that is referred to as a junction.

You can also get mount point information via Windows Management Instrumentation (WMI) with the Win32_MountPoint class. Here's how using Windows PowerShell.

PS C:\> get-wmiobject win32_mountpoint | format-list Directory,Volume
Directory : Win32_Directory.Name="C:\\work\\vhd"
Volume''' : Win32_Volume.DeviceID="\\\\?\\Volume{2dd97d8a-3bab-11e1-b9ff-080027e238aa}\\"
Directory : Win32_Directory.Name="C:\\"
Volume''' : Win32_Volume.DeviceID="\\\\?\\Volume{8130d5f4-8e9b-11de-b460-806e6f6e6963}\\"
Directory : Win32_Directory.Name="E:\\"
Volume''' : Win32_Volume.DeviceID="\\\\?\\Volume{f0c6247d-9006-11df-9f42-080027e238aa}\\"
Directory : Win32_Directory.Name="A:\\"
Volume''' : Win32_Volume.DeviceID="\\\\?\\Volume{897cdd66-2574-11df-95ac-806e6f6e6963}\\"
Directory : Win32_Directory.Name="D:\\"
Volume''' : Win32_Volume.DeviceID="\\\\?\\Volume{897cdd65-2574-11df-95ac-806e6f6e6963}\\"

So how do we work with these beasties? Well, there are a few tools you can get your hands on.

First, let's revisit Mountvol.exe. If you know the path to your mounted volume, you can retrieve it like this:

C:\Users\jeff>mountvol c:\work\vhd /L
\\?\Volume{2dd97d8a-3bab-11e1-b9ff-080027e238aa}

The volume can be dismounted but you must be in an elevated session.

C:\Windows\system32>mountvol c:\work\vhd /D

To re-mount you need to know the volume name. Again, this must be performed in an elevated session:

C:\Windows\system32>mountvol c:\work\vhd \\?\Volume{2dd97d8a-3bab-11e1-b9ff-080027e238aa}\

But that's a lot to remember and in the case of VHD, it must be attached to the filesystem. The easy way is to user the Disk Management management console. But if you are looking for a more programmatic approach, you'll need to resort to the command line, most likely using Diskpart.exe.

C:\Windows\system32>diskpart

Microsoft DiskPart version 6.1.7600
Copyright (C) 1999-2008 Microsoft Corporation.
On computer: CHI-WIN7-22

DISKPART> select vdisk file=e:\myextraspace.vhd

DiskPart successfully selected the virtual disk file.

DISKPART> attach vdisk

100 percent completed

DiskPart successfully attached the virtual disk file.

DISKPART>

Now, before we can mount this to a folder, we need to know the volume number.

DISKPART> list volume

Volume ###' Ltr' Label''''''' Fs'''' Type''''''' Size'''' Status'''' Info
----------' ---' -----------' -----' ----------' -------' ---------' ----
Volume 0'''' E'' New Volume'' NTFS'' Simple''''' 4093 MB' Healthy
Volume 1'''' D'' VBOXADDITIO' CDFS'' CD-ROM''''''' 43 MB' Healthy
Volume 2'''''''' System Rese' NTFS'' Partition''' 100 MB' Healthy''' Syst
Volume 3'''' C''''''''''''''' NTFS'' Partition'''' 24 GB' Healthy''' Boot
Volume 4'''''''' New Volume'' NTFS'' Partition''' 247 MB' Healthy

I want the last volume.

DISKPART> select volume 4

Volume 4 is the selected volume.

DISKPART> assign mount=c:\work\vhd

DiskPart successfully assigned the drive letter or mount point.

If I dismount and remount, Windows will re-use this mount path, unless I remove it.

DISKPART> remove mount=c:\work\vhd

DiskPart successfully removed the drive letter or mount point.

DISKPART> detach vdisk

DiskPart successfully detached the virtual disk file.

Honestly, Windows 7 doesn't include a simple utility for finding, adding or removing mount points. Fortunately, you can download a free utility from the Sysinternals site on Microsoft.com called Junctions.exe. Go to http://technet.microsoft.com/en-us/sysinternals/bb896768 and download the utility. I put it in C:\Windows\System32 so I can access it from any folder.

If you run the command without any parameters, you'll see how to use it.


Figure 6 Junction.exe

It still helps if you know the junction path.

C:\Users\jeff>junction c:\work\vhd

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

c:\work\vhd: MOUNT POINT
Print Name'''' : \??\Volume{2dd97d8a-3bab-11e1-b9ff-080027e238aa}Substitute Name: Volume{2dd97d8a-3bab-11e1-b9ff-080027e238aa}

Or even if you know part of the folder to search for junctions you can use the 's parameter to recurse as I've done in Figure 7.


Figure 7 Recursive Junction Search

To delete a junction is extremely easy. Here's how I can delete my VHD junction.

C:\Users\jeff>junction -d c:\work\vhd

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Deleted c:\work\vhd.

And of course, I can use junction.exe to create a junction as long as I know the target name.

C:\>junction c:\work\vhd \\?\Volume{2dd97d8a-3bab-11e1-b9ff-080027e238aa}
Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Created: c:\work\vhd
Targetted at: \\?\Volume{2dd97d8a-3bab-11e1-b9ff-080027e238aa}

Creating junctions with volumes is admittedly difficult because you have to figure out that long volume name. But you can also create what I think of as simple junctions, that redirect file I/O to a different folder.

C:\>junction c:\work\data e:\foodata

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Created: c:\work\data

Targetted at: e:\foodata

I just created a reparsepoint for c:\work\data that points to e:\foodata. The source folder will be created when you run the command. You can either create the target folder before or after you run the command. But from then on files that look like they are in C:\Data are actually in E:\foodata.

C:\work>dir data /w
Volume in drive C has no label.
Volume Serial Number is A4BA-3EFF

Directory of C:\work\data

[.]''''''''''''''' [..]'''''''''''''' dcperf.csv'''''''' diskutil.csv
file.txt'''''''''' fp01-drivers.csv'' newhires.csv'''''' svcdata.csv
sysdrivers.csv'''' testbatt.csv
8 File(s)''''''' 179,988 bytes
2 Dir(s)'' 3,163,054,080 bytes free
C:\work>dir e:\foodata /w
Volume in drive E is New Volume
Volume Serial Number is 7C61-4082

Directory of e:\foodata

[.]''''''''''''''' [..]'''''''''''''' dcperf.csv'''''''' diskutil.csv
file.txt'''''''''' fp01-drivers.csv'' newhires.csv'''''' svcdata.csv
sysdrivers.csv'''' testbatt.csv
8 File(s)''''''' 179,988 bytes
2 Dir(s)'' 3,163,054,080 bytes free

Any Windows program will seamlessly access files on the E: drive through this junction. You might use this technique to easily insert a USB drive into a given folder path.

One thing to keep in mind is that the target location must be formatted as NTFS and a local drive. You cannot create a junction that points to a UNC. Or rather, you can't create a functioning link. The junction.exe tool will create the junction pointing to the UNC, or a mapped drive, but it won't work.

The last type of link creature in the menagerie you might need to tame, or maybe let run wild is a hard link. Up to now we have been primarily looking at symbolic links at the folder level. But we can also create links at the file level. Actually, every file automatically has a hard link. This is a directory entry for the file in NTFS. When you access a file, the file system knows where to find the bits on the NTFS volume. But, you can have multiple hardlinks. This means that you can have a single file appear in multiple locations. Or you can have multiple links in the same directory, as long as names are unique. Personally, I think the first option is of more use.

To work with hardlinks we'll turn again to fsutil.exe. Remember, this must be run in an elevated session. To demonstrate I have a single file in my Work directory.

C:\Windows\system32>fsutil hardlink list c:\work\hardlinked.txt\work\hardlinked.txt

As you can see it is linked to its original location. But now I'm going to add a second hard link with one caveat: both files must be on the same volume. Even if you try creating the link in a folder that has a junction, Windows will know.

C:\Windows\system32>fsutil hardlink create c:\work\data\hardlinked2.txt c:\work\hardlinked.txt

The new link and the existing file must be on the same volume.

Instead you will need to do something like this:

C:\Windows\system32>fsutil hardlink create c:\backup\hardlinked.txt c:\work\hardlinked.txt

Hardlink created for c:\backup\hardlinked.txt <<===>> c:\work\hardlinked.txt

C:\Windows\system32>fsutil hardlink list c:\work\hardlinked.txt
\work\hardlinked.txt
\backup\hardlinked.txt

I specify the new file first, then the file I'm linking. Now the file is in two places at once.

C:\work>dir hardlinked.txt
Volume in drive C has no label.
Volume Serial Number is A4BA-3EFF

Directory of C:\work

11/20/2011' 03:46 PM'''''''''''''' 144 hardlinked.txt
1 File(s)''''''''''' 144 bytes
0 Dir(s)'' 9,050,337,280 bytes free

C:\work>dir c:\backup\hardlinked.txt
Volume in drive C has no label.
Volume Serial Number is A4BA-3EFF

Directory of c:\backup

11/20/2011' 03:46 PM'''''''''''''' 144 hardlinked.txt
1 File(s)''''''''''' 144 bytes
0 Dir(s)'' 9,050,337,280 bytes free
C:\work>

If I make a change to the file, in either location, the file is updated in both locations. Technically the file is updated once but there are two links to the file data. You can have as many links as you need. The files don't even need to have the same name.

C:\Windows\system32>fsutil hardlink create c:\save\1.txt c:\work\hardlinked.txt
Hardlink created for c:\save\1.txt <<===>> c:\work\hardlinked.txt

C:\Windows\system32>fsutil hardlink list c:\work\hardlinked.txt
\save\1.txt
\work\hardlinked.txt
\backup\hardlinked.txt

If you use hard links, be aware that the file is only truly deleted from the file system once you delete all of its hard links. I've deleted the 'original' file, but it is still available in other location.

C:\Windows\system32>fsutil hardlink list c:\work\hardlinked.txt
Error:' The system cannot find the file specified.

C:\Windows\system32>fsutil hardlink list c:\backup\hardlinked.txt
\save\1.txt
\backup\hardlinked.txt

I would have to delete all copies in order to fully delete the file. On the other hand, if this is a critical file that I accidentally deleted, I can recover it by creating a new link using the original file name.

C:\Windows\system32>fsutil hardlink create c:\work\hardlinked.txt c:\save\1.txt
Hardlink created for c:\work\hardlinked.txt <<===>> c:\save\1.txt

Before we wrap up let me address one limiting factor: you have to specify the file path. This makes it cumbersome if you wanted to check all files in a folder or volume. But, I put together a relatively simple PowerShell function that wraps up fsutil.exe. Download the Get-Hardlink.ps1 here and load it into your PowerShell session. The function will write a custom object to the pipeline. I've designed the function so that you can do a directory listing and pipe the results to the function. Figure 8 demonstrates the function in action.


Figure 8 Get-Hardlink Example

I expect most of the time you will have objects with a Count of 1 and MultipleLinks value of False. But we can use this to find only files with links.

PS C:\> dir c:\work\ | get-hardlink | where {$_.MultipleLinks} | format-list

Count'''''''' : 3
Path''''''''' : C:\work\hardlinked.txt
Links'''''''' : {\save\1.txt, \work\hardlinked.txt, \backup\hardlinked.txt}
MultipleLinks : True

As we've seen, there are a few ways to be in more than one place. Perhaps you want to take advantage of these features to meet your own business requirements. At the very least you now have the tools you need to troubleshoot reparse points and hard links.