It is not that simple to create relative symbolic links in powershell 5.1. New-Item
is not working as expected. Some approaches are listed below. Am I missing something?
Sample setup for all examples:
mkdir C:\Temp\foo -ErrorAction SilentlyContinue
'sample contents' > C:\Temp\foo\foo.txt
cd C:\Temp
Sample1: Does not work as expected
#new ps5 Item cmdlets (https://msdn.microsoft.com/en-us/powershell/wmf/5.0/feedback_symbolic) are not working well with relative paths
#C:\Temp\foo and C:\Temp\foo\foo.txt are returned
$fld = New-Item -ItemType SymbolicLink -Name 'bar' -Target '.\foo'
$fl = New-Item -ItemType SymbolicLink -Name 'bar.txt' -Target '.\foo\foo.txt'
$fld.Target
$fl.Target
Sample2: Does not work as expected
#Powershell community extensions
#same problem - paths are created as absolute: C:\Temp\foo C:\Temp\foo\foo.txt
$fld = New-Symlink 'c:\Temp\bar' '.\foo'
$fl = New-Symlink 'c:\Temp\bar.txt' '.\foo\foo.txt'
$fld.Target
$fl.Target
Sample3: Works as expected
#API call CreateSymbolicLink as per https://gallery.technet.microsoft.com/scriptcenter/new-symlink-60d2531e
#.\foo and .\foo\foo.txt are returned
Add-Type -MemberDefinition @'
[DllImport("kernel32.dll", EntryPoint = "CreateSymbolicLinkW", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);
public static DirectoryInfo CreateSymbolicLinkToFolder(string lpSymlinkFileName, string lpTargetFileName) {
bool res = CreateSymbolicLink(lpSymlinkFileName, lpTargetFileName, 1);
if (!res) { throw new Win32Exception(Marshal.GetLastWin32Error()); }
return (new DirectoryInfo(lpSymlinkFileName));
}
public static FileInfo CreateSymbolicLinkToFile(string lpSymlinkFileName, string lpTargetFileName) {
bool res = CreateSymbolicLink(lpSymlinkFileName, lpTargetFileName, 0);
if (!res) { throw new Win32Exception(Marshal.GetLastWin32Error()); }
return (new FileInfo(lpSymlinkFileName));
}
'@ -Name Win32 -NameSpace System -UsingNamespace System.ComponentModel, System.IO
[Win32]::CreateSymbolicLinkToFolder("c:\Temp\bar", ".\foo")
[Win32]::CreateSymbolicLinkToFile("c:\Temp\bar.txt", ".\foo\foo.txt")
Sample4: Works as expected
#using mklink from cmd produces correct relative paths
#.\foo and .\foo\foo.txt are returned
cmd /c mklink /d "c:\Temp\bar" ".\foo"
cmd /c mklink "c:\Temp\bar.txt" ".\foo\foo.txt"
(Get-Item "c:\Temp\bar").Target
(Get-Item "c:\Temp\bar.txt").Target
Edit: Sample3 has been updated to unicode api entry and GetLastError
As the most common shells expands paths, to create a relative symlink you should quote the "source path". Also, the -s parameter means --symbolic . ln creates hard links by default.
Call the New-Item cmdlet to create symbolic links and pass in the item type SymbolicLink . Next, replace the Link argument with the path to the symbolic link we want to make (including the file name and its extension). Finally, replace the Target portion with the path (relative or absolute) that the new link refers to.
Symbolic link can be of two types Relative or Absolute.
Starting with pwsh 7.1.X sample1 works as expected:
#new ps5 Item cmdlets (https://msdn.microsoft.com/en-us/powershell/wmf/5.0/feedback_symbolic) are not working well with relative paths
#C:\Temp\foo and C:\Temp\foo\foo.txt are returned
$fld = New-Item -ItemType SymbolicLink -Name 'bar' -Target '.\foo'
$fl = New-Item -ItemType SymbolicLink -Name 'bar.txt' -Target '.\foo\foo.txt'
$fld.Target
$fl.Target
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With