Skip to content

Issue with Creating Symbolic Links in PowerShell (pwsh) using New-Item and mklink Commands #25187

@IlluminatiWave

Description

@IlluminatiWave

Prerequisites

Steps to reproduce

Summary:

This report details an issue with inconsistencies when trying to create symbolic links using PowerShell (pwsh), both with the New-Item -ItemType SymbolicLink command and the mklink /D command in the Windows environment. The problem arises when using relative paths, which in some cases are not resolved correctly, causing the symbolic links to not be created as expected. Additionally, PowerShell lacks a clear option like -LiteralPath, which can cause issues when working with paths containing special characters like brackets.


Problem Description:

In a working directory C:\test symlinks, several tests were performed to create symbolic links (both files and directories) using PowerShell and mklink. The behavior of the commands was inconsistent, especially when working with relative paths, which sometimes failed to resolve correctly, resulting in failed symbolic link creation.

The erratic behavior was particularly focused on creating symbolic links with relative paths using PowerShell, as the paths were sometimes resolved unexpectedly, leading to failure in creating the symbolic links.


Steps to Reproduce the Problem:

  1. Create the base folders and subfolders:

    A folder structure was created in C:\test symlinks with the following subfolders:

    • original items
    • pwsh links
    • cmd links
  2. Create items inside original items:

    A folder (test_folder) and a text file (test_file.txt) were added to the original items folder.

  3. Script used to create symbolic links:

    The following script was used to create symbolic links with both PowerShell and the mklink command in CMD:

    function New-Symlink {
        param (
            [string]$originalDir,  # Folder where the original files are located
            [string]$itemName      # Name of the file or folder to link
        )
    
        # Absolute paths for symbolic links
        $pwshLinkPath = "$pwshLinksDir\$itemName"
        $cmdLinkPath = "$cmdLinksDir\$itemName"
        
        # Relative path from the symbolic link to the original
        $relativeTarget = "..\..\test symlinks\original items\$itemName"
    
        # Determine if the original is a file or a folder
        $originalPath = "$originalDir\$itemName"
        $isDirectory = Test-Path $originalPath -PathType Container
    
        if (-not (Test-Path $pwshLinkPath)) {
            # Create with PowerShell
            if ($isDirectory) {
                New-Item -ItemType SymbolicLink -Path $pwshLinkPath -Target $relativeTarget | Out-Null
            } else {
                New-Item -ItemType SymbolicLink -Path $pwshLinkPath -Target $relativeTarget -Force | Out-Null
            }
            Write-Host "[INFO] Symbolic link (PowerShell) created: $pwshLinkPath -> $relativeTarget"
        }
    
        if (-not (Test-Path $cmdLinkPath)) {
            # Create with CMD (using quotes for paths with spaces)
            if ($isDirectory) {
                cmd /c "mklink /D `"$cmdLinkPath`" `"$relativeTarget`"" | Out-Null
            } else {
                cmd /c "mklink `"$cmdLinkPath`" `"$relativeTarget`"" | Out-Null
            }
            Write-Host "[INFO] Symbolic link (CMD) created: $cmdLinkPath -> $relativeTarget"
        }
    }
    
    $baseDir = "C:\test symlinks"
    $originalItemsDir = "$baseDir\original items"
    
    # Call the function to create the symbolic links
    New-Symlink -originalDir $originalItemsDir -itemName "test_folder"
    New-Symlink -originalDir $originalItemsDir -itemName "test_file.txt"

Observed Behavior:

  1. In PowerShell (without administrator privileges):

    • The PowerShell command successfully creates symbolic links when run directly in the console.
    • However, when run from a script, the behavior is inconsistent, and symbolic links are not always created correctly, especially when working with folders. Sometimes, relative paths are not resolved correctly, leading to errors or unexpected behavior.
  2. In PowerShell Core (pwsh):

    • The command resolves the paths correctly and without errors, even without administrator privileges. This occurs in Windows 11, where path resolution seems to be more reliable compared to older versions of PowerShell.
  3. mklink /D Command in CMD:

    • When used with a directory, the /D flag allows creating a "directory" symbolic link that points to a target folder. This flag should only be used with directories. Using it with a file will create a symbolic link that points to a folder, which causes errors when accessing the link.

    • When used with a file, the /D flag should be omitted, as mklink will automatically create a file symbolic link. Using /D with a file creates a directory symbolic link, which is invalid and can lead to errors when trying to access the link.

    Correct usage of mklink:

    • To create a directory symbolic link (with /D):
      mklink /D "C:\test symlinks\cmd links\test_folder" "C:\test symlinks\original items\test_folder"
    • To create a file symbolic link (without /D):
      mklink "C:\test symlinks\cmd links\test_file.txt" "C:\test symlinks\original items\test_file.txt"

Additional Observations on Relative Paths and PowerShell:

  1. Inconsistent Resolution of Relative Paths:

    The erratic behavior observed seems to be related to the resolution of relative paths when creating symbolic links in PowerShell. While PowerShell can resolve relative paths reliably in some cases, in others it fails to do so correctly, causing the symbolic links not to be created properly, especially when working with folders. In some cases, a folder (like test_folder) is created as a file, indicating an issue with the interpretation of relative paths.

  2. Ambiguity in Using New-Item and -LiteralPath:

    One major limitation of PowerShell is that it does not have a clear parameter like -LiteralPath in the New-Item cmdlet. This can be problematic when scanning folders that contain special characters in their names (e.g., brackets). When attempting to process these paths inside a script that lists and processes relative paths, the behavior may not be as expected, as PowerShell does not always handle these characters correctly, leading to errors or unexpected behavior.

Expected behavior

PS C:\> (Get-Item "C:\test symlinks\pwsh links\test_folder").PSIsContainer
True

Actual behavior

PS C:\> (Get-Item "C:\test symlinks\pwsh links\test_folder").PSIsContainer
True (sometimes False)

Environment data

Name                           Value
----                           -----
PSVersion                      7.4.7
PSEdition                      Core
GitCommitId                    7.4.7
OS                             Microsoft Windows 10.0.27802
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

The error also persists in

Name                           Value
----                           -----
PSVersion                      7.6.0-preview.3
PSEdition                      Core
GitCommitId                    7.6.0-preview.3
OS                             Microsoft Windows 10.0.27802
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    In-PRIndicates that a PR is out for the issueNeeds-TriageThe issue is new and needs to be triaged by a work group.Resolution-FixedThe issue is fixed.WG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    Status

    Reviewed

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions