powershell symlink junction

PowerShell para resolver la ruta de destino de unión



symlink junction (4)

En PowerShell, necesito resolver la ruta de destino de una unión (enlace simbólico).

por ejemplo, digamos que tengo una unión c:/someJunction cuyo destino es c:/temp/target

$junc = Get-Item c:/someJunction variaciones de $junc = Get-Item c:/someJunction , pero solo pude obtener c:/someJunction

¿Cómo puedo encontrar la ruta de destino de la unión, en este ejemplo c:/temp/target , de una unión determinada?


Se ha mejorado New-Item, Remove-Item y Get-ChildItem para permitir la creación y administración de enlaces simbólicos. El parámetro -ItemType para New-Item acepta un nuevo valor, SymbolicLink. Ahora puede crear enlaces simbólicos en una sola línea ejecutando el cmdlet New-Item.

Novedades en Windows PowerShell v5

He comprobado la compatibilidad del enlace simbólico en mi máquina con Windows 7, funciona bien.

> New-Item -Type SymbolicLink -Target C: -Name TestSymlink Directory: C:/Users/skokhanovskiy/Desktop Mode LastWriteTime Length Name ---- ------------- ------ ---- d----l 06.09.2016 18:27 TestSymlink

Obtén el objetivo del enlace simbólico tan fácil como crearlo.

> Get-Item ./TestSymlink | Select-Object -ExpandProperty Target C:/


Esto hace el truco con menos trabajo y funciona incluso para uniones en un servidor remoto:

fsutil reparsepoint query "M:/Junc"

Si quieres solo el nombre del objetivo:

fsutil reparsepoint query "M:/Junc" | where-object { $_ -imatch ''Print Name:'' } | foreach-object { $_ -replace ''Print Name/:/s*'','''' }

asi que

function Get_JunctionTarget($p_path) { fsutil reparsepoint query $p_path | where-object { $_ -imatch ''Print Name:'' } | foreach-object { $_ -replace ''Print Name/:/s*'','''' } }

Además, el siguiente código es una ligera modificación del código que Josh proporcionó anteriormente. Se puede colocar en un archivo que se lee varias veces y se maneja correctamente el //?/ Líder en el caso de una unidad de red:

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) }

y dada la función Get_UNCPath anterior, podemos mejorar la función Get_JunctionTarget siguiente manera:

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 }


Puedes obtener el camino haciendo lo siguiente:

Get-ChildItem -Path C:/someJunction

Editar para encontrar la ruta y no el contenido de la carpeta

Add-Type -MemberDefinition @" 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(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 if (path[0] == ''//' && path[1] == ''//' && path[2] == ''?'' && path[3] == ''//') return path.ToString().Substring(4); else return path.ToString(); } "@ -Name Win32 -NameSpace System -UsingNamespace System.Text,Microsoft.Win32.SafeHandles,System.ComponentModel $dir = Get-Item D:/1 [System.Win32]::GetSymbolicLinkTarget($dir)


Terminamos usando esta función.

function Get-SymlinkTargetDirectory { [cmdletbinding()] param( [string]$SymlinkDir ) $basePath = Split-Path $SymlinkDir $folder = Split-Path -leaf $SymlinkDir $dir = cmd /c dir /a:l $basePath | Select-String $folder $dir = $dir -join '' '' $regx = $folder + ''/ */[(.*?)/]'' $Matches = $null $found = $dir -match $regx if ($found) { if ($Matches[1]) { Return $Matches[1] } } Return '''' }