Create symbolic links in .NET

 
 
  • Gérald Barré

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:

Shell
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:

NativeMethods.txt
CreateSymbolicLink

Finally, add the following code to your Program.cs file:

Program.cs (C#)
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!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub