Skip to content

Instantly share code, notes, and snippets.

@Trucido
Last active April 15, 2019 00:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Trucido/dcd6d49f6c9533c4832c84d7f92854b5 to your computer and use it in GitHub Desktop.
Save Trucido/dcd6d49f6c9533c4832c84d7f92854b5 to your computer and use it in GitHub Desktop.
## Get-LinkTarget.ps1
# Note: Script should be symlinked as follows:
# Get-LinkTarget.ps1 -> Resolve-UNCPath.ps1
# Get-LinkTarget.ps1 -> Resolve-JunctionPath.ps1
# Get-LinkTarget.ps1 -> Resolve-HardlinkPath.ps1
# Get-LinkTarget.ps1 -> Resolve-SymlinkPath.ps1
# Get-LinkTarget.ps1 -> Resolve-ReparsePointPath.ps1
function Global:Get_UNCPath($l_dir)
{
if( ( ([System.Management.Automation.PSTypeName]'System.Win32').Type -eq $null) -or
([system.win32].getmethod('GetSymbolicLinkTarget') -eq $null ) )
{
Add-Type -MemberDefinition @"
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(System.IO.DirectoryInfo symlink)
{
SafeFileHandle directoryHandle = CreateFile(symlink.FullName, 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());
}
// The remarks section of GetFinalPathNameByHandle mentions the return being prefixed with "\\?\"
// More information about "\\?\" here -> http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx
string sPath = path.ToString();
if( sPath.Length>8 && sPath.Substring(0,8) == @"\\?\UNC\" )
{
return @"\" + sPath.Substring(7);
}
else if( sPath.Length>4 && sPath.Substring(0,4) == @"\\?\" )
{
return sPath.Substring(4);
}
else
{
return sPath;
}
}
"@ -Name Win32 -NameSpace System -UsingNamespace System.Text,Microsoft.Win32.SafeHandles,System.ComponentModel
}
[System.Win32]::GetSymbolicLinkTarget($l_dir)
}
function Global:Get_JunctionTarget([string]$p_path)
{
$l_target = fsutil reparsepoint query $p_path | where-object { $_ -imatch 'Print Name\:' } | foreach-object { $_ -replace 'Print Name\:\s*','' }
if( $l_target -imatch "(^[A-Z])\:\\" )
{
$l_drive = $matches[1]
$l_uncPath = Get_UncPath $p_path
if( $l_uncPath -imatch "(^\\\\[^\\]*\\)" )
{
$l_machine = $matches[1]
$l_target = $l_target -replace "^$l_drive\:","$l_machine$l_drive$"
}
}
$l_target
}
function Global:Get_LinkTargetPath
{
foreach($item in $args)
{
$itemTarget = try { (Get-Item $item -Force).Target } catch {}
if( !$itemTarget )
{
continue
}
if( $itemTarget)
{
$itemTarget # TODO: resolve target PSPath
}
}
}
if( !( $MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -eq '' ) )
{
if( $null -ne $MyInvocation.MyCommand.Name )
{
switch -Wildcard ( $MyInvocation.MyCommand.Name )
{
"*UNC*" { Get_UNCPath $args }
"*Junction*" { Get_JunctionPath $args }
"*Reparse*" { Get_JunctionPath $args }
"*Sym*" { Get_LinkTargetPath $args }
"*Hard*" { Get_LinkTargetPath $args }
}
}
}
else {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment