Create symbolic links in .NET
Symbolic link allows to create a link to a file or directory. The symbolic link is a second file that exists independently of its target. If a symbolic link is deleted, its target remains unaffected. If the target is deleted, the symbolic link is not automatically removed. This is different from hard links which always refer to an existing file.
Windows allows creation of symbolic links since Windows Vista. However, creating symbolic links requires administrative privileges. You can enable Developer Mode to create symbolic links without administrative privileges. On Linux, you can create symbolic links without administrative privileges.
To create a symbolic link in .NET, you can use the CreateSymbolicLink
function on Windows and the posix function on other systems. To avoid doing the PInvoke yourself, you can use the Microsoft.Windows.CsWin32
package that provides a managed API for Windows functions. For Posix, you can use the Mono.Posix.NETStandard
package.
Let's create a new console application and add the required packages:
dotnet new console
dotnet add package Mono.Posix.NETStandard
dotnet add package Microsoft.Windows.CsWin32
Add a file named NativeMethods.txt
with the following content:
CreateSymbolicLink
Finally, add the following code to your Program.cs
file:
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Windows.Win32;
using Windows.Win32.Storage.FileSystem;
CreateSymbolicLink("link", "target_file_or_folder");
static void CreateSymbolicLink(string symlinkPath, string targetPath)
{
if (OperatingSystem.IsWindows())
{
if (!OperatingSystem.IsWindowsVersionAtLeast(6, 0, 6000))
throw new Win32Exception("Only supported on Windows 6.0.6000");
CreateSymbolicLinkWindows(symlinkPath, targetPath);
}
else
{
CreateSymbolicLinkPosix(symlinkPath, targetPath);
}
}
[SupportedOSPlatform("windows6.0.6000")]
static void CreateSymbolicLinkWindows(string symlinkPath, string targetPath)
{
var flags = SYMBOLIC_LINK_FLAGS.SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
if (Directory.Exists(targetPath))
{
flags |= SYMBOLIC_LINK_FLAGS.SYMBOLIC_LINK_FLAG_DIRECTORY;
}
if (!PInvoke.CreateSymbolicLink(symlinkPath, targetPath, flags))
{
var error = Marshal.GetLastWin32Error();
throw new Win32Exception(error, "Cannot create the symbolic link. You may need to enable Developer Mode or run the tests as admin.");
}
}
static void CreateSymbolicLinkPosix(string symlinkPath, string targetPath)
{
var result = Mono.Unix.Native.Syscall.symlink(targetPath, symlinkPath);
if (result != 0)
{
var error = Mono.Unix.Native.Stdlib.GetLastError();
throw new Win32Exception((int)error, "Cannot create the symbolic link: " + error);
}
}
Do you have a question or a suggestion about this post? Contact me!