I wrote this function to locate pointers across files and directories to verify where its source information gets gathered from. It uses a C# method and a PowerShell wrapper, and may be useful for those who need to quickly locate a symbolic link to a file or directory so I figured I'd toss it on here for anyone who wants to use it. Code: #region C# Code Method Add-Type @" using System; using System.Text; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using System.ComponentModel; namespace LINK_INTEROP { public sealed class GetSymbolicLink { private const int FILE_SHARE_READ = 1; private const int FILE_SHARE_WRITE = 2; private const int CREATION_DISPOSITION_OPEN_EXISTING = 3; private const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; [DllImport("kernel32.dll", EntryPoint = "GetFinalPathNameByHandleW", CharSet = CharSet.Unicode, SetLastError = true)] public static extern int GetFinalPathNameByHandle ( IntPtr handle, [In, Out] StringBuilder path, int bufLen, int flags ); [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)] public static extern SafeFileHandle CreateFile ( string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr SecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile ); public static string GetSymbolicLinkTarget(string SymbolicLinkPath) { SafeFileHandle directoryHandle = CreateFile ( SymbolicLinkPath, 0, 2, System.IntPtr.Zero, CREATION_DISPOSITION_OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, System.IntPtr.Zero ); if ( directoryHandle.IsInvalid ) throw new Win32Exception ( Marshal.GetLastWin32Error() ); StringBuilder path = new StringBuilder(512); int size = GetFinalPathNameByHandle (directoryHandle.DangerousGetHandle(), path, path.Capacity, 0 ); if (size < 0) throw new Win32Exception ( Marshal.GetLastWin32Error() ); if (path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\') return path.ToString().Substring(4); else return path.ToString(); } } } "@ #endregion C# Code Method Function Get-SymbolicLink { <# .SYNOPSIS Gets symbolic links from a regular resolvable path. .DESCRIPTION Gets the link of an INODE/file that points to another INODE/file. This allows for verification of true information INODE\link locations. .PARAMETER Path The resolvable path of any file or directory to check for Symbolic Links. .EXAMPLE PS C:\> Get-SymbolicLink -Path "C:\Documents and Settings" .NOTES Symbolic Links are how data is stored on drives. Being able to "track" them allows a user to locate pointers (paths) an INODE/file may use to access information. #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)][ValidateNotNullOrEmpty()][string]$Path ) Process { Return [LINK_INTEROP.GetSymbolicLink]::GetSymbolicLinkTarget($Path) } }
I should have also made it clear that this particular function does no changes to either the symbolic link or anything that would harm a system. It simply shows you where a specific file/INODE points to allowing you to verify information pointers and sources. This can be very useful if trying to track down resolvable paths for any item that uses a symbolic link, which most do. If you're unfamiliar with Symbolic Links, think of them as advanced Junction Points, where an alias is used for data access and not the actual hard-link where the information is truly located.