Home Dashboard Directory Help
Search

Need PowerShell equivalent to Cmd's "mklink" by Charlie Russel - MVP


Status: 

Active


30
0
Sign in
to vote
Type: Suggestion
ID: 627099
Opened: 12/2/2010 10:06:36 AM
Access Restriction: Public
3
Workaround(s)
view

Description

In my ongoing desire to eliminate the need for CMD, the one remaining functionality I can't find a workaround for is the CMD internal "mklink" that allows you to make hard or symbolic links in the filesystem. Please add this the next version of PowerShell!

Thanks,

Charlie Russel
(PowerShell MVP)
Details
Sign in to post a comment.
Posted by Sen Harada on 2/13/2012 at 10:35 PM
Native support for creating a link is really needed. Calling cmd.exe doesn't provide error information if the command fails.

I don't think complicated operations should be supported natively. They should be done by an add-on like PSCX. But this is a very basic operation. I really wonder why this is not supported NATIVELY by PowerShell.
Sign in to post a workaround.
Posted by Jordan Mills on 1/15/2014 at 5:21 PM
#symlinks.ps1

# First add a type so it stays available for this instance
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

namespace mklink
{
    public class symlink
    {
        [DllImport("kernel32.dll")]
        public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);
        [DllImport("kernel32.dll")]
        public static extern bool RemoveDirectory(string lpPathName);
        [DllImport("kernel32.dll")]
        public static extern uint GetLastError();
    }
}
'@

Function New-ReparsePoint() {
     <#
    .SYNOPSIS
        Creates a reparse point to the specified target.
        
    .DESCRIPTION
        Creates a reparse point to the specified target.
        
    .PARAMETER Path
        Path to the reparse point to remove.
        
    .NOTES
        Author: Jordan Mills
        Version: 1.0
    
    .EXAMPLE
        Remove-SymbolicLink -Path "E:\directory\mount"
    #>    
    [cmdletbinding(DefaultParameterSetName="default")]
    Param (
        [parameter(
            ParameterSetName="default",
            Position=0,
            Mandatory=$true,
            ValueFromPipeLine=$True,
            ValueFromPipelineByPropertyName=$True
        )]
        [parameter(
            ParameterSetName="file",
            Position=0,
            Mandatory=$true,
            ValueFromPipeLine=$True,
            ValueFromPipelineByPropertyName=$True
        )]
        [parameter(
            ParameterSetName="directory",
            Position=0,
            Mandatory=$true,
            ValueFromPipeLine=$True,
            ValueFromPipelineByPropertyName=$True
        )]
        [Alias("Path","FileName","Directory")]
        [string[]]$Name,
        [parameter(
            ParameterSetName="default",
            Position=1,
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$True
        )]
        [parameter(
            ParameterSetName="file",
            Position=1,
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$True
        )]
        [parameter(
            ParameterSetName="directory",
            Position=1,
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$True
        )]
        [string]$TargetPath,
        [parameter(
            ParameterSetName="file",
            Position=2,
            Mandatory=$false,
            ValueFromPipelineByPropertyName=$True
        )]
        [switch]$IsFile,
        [parameter(
            ParameterSetName="directory",
            Position=2,
            Mandatory=$false,
            ValueFromPipelineByPropertyName=$True
        )]
        [switch]$IsDirectory
    )

    If ($IsFile -or $IsDirectory) {
        If($IsFile) {
            $result = [mklink.symlink]::CreateSymbolicLink($Name,$TargetPath,0)
        }
        Else {
            If($IsDirectory) {
                $result = [mklink.symlink]::CreateSymbolicLink($Name,$TargetPath,1)
            }
            Else {
                Write-Error -Message "Conflicting path type parameters. This should not happen."
                Break;
            }
        }
    }
    Else {
        If (Test-Path -LiteralPath $TargetPath -PathType Leaf -ErrorAction SilentlyContinue) {
            $result = [mklink.symlink]::CreateSymbolicLink($Name,$TargetPath,0)
        }
        Else {
            If (Test-Path -LiteralPath $TargetPath -PathType Container -ErrorAction SilentlyContinue) {
                $result = [mklink.symlink]::CreateSymbolicLink($Name,$TargetPath,1)
            }
            Else {
                Write-Error -Message "Unable to determine path type of TargetPath. Use -IsFile or -IsDirectory."
                Break;
            }
        }
    }

    If ($result) {
        Get-Item $Name
    } Else {
        Write-Error -Message "Error creating symbolic link" -Category WriteError #-ErrorId $([mklink.symlink]::GetLastError())
    }
}

Function Remove-ReparsePoint {
     <#
    .SYNOPSIS
        Removes a file or directory that is a reparse point (symlink or hardlink) without removing all child objects.
        
    .DESCRIPTION
        Removes a file or directory that is a reparse point (symlink or hardlink) without removing all child objects.
        
    .PARAMETER Path
        Path to the reparse point to remove.
        
    .NOTES
        Author: Jordan Mills
        Version: 1.0
    
    .EXAMPLE
        Remove-SymbolicLink -Path "E:\directory\mount"
    #>    
    [cmdletbinding()]
    Param (
        [parameter(
            Position=0,
            Mandatory=$true,
            ValueFromPipeLine=$True,
            ValueFromPipelineByPropertyName=$True
        )]
        [Alias("FullName","Name","FileName","Directory")]
        [ValidateScript({Test-Path $_})]
        [string[]]$Path
    )
    
    $Path |
    Get-Item |
    ForEach-Object {
        $Item = $_;
        Switch ($Item.Attributes -band ([IO.FileAttributes]::ReparsePoint -bor [IO.FileAttributes]::Directory)) {
            ([IO.FileAttributes]::ReparsePoint -bor [IO.FileAttributes]::Directory) {
                # Is reparse directory / symlink
                If ($whatif) {
                    Write-Host "What if: Performing the operation `"Delete Directory`" on target `"$($_.FullName)`""
                } Else {
                    [System.IO.Directory]::Delete($Item.FullName);
                    Break;
                }
            }
            ([IO.FileAttributes]::ReparsePoint -bor 0) {
                # Is reparse file / hardlink
                If ($whatif) {
                    Write-Host "What if: Performing the operation `"Delete File`" on target `"$($_.FullName)`""
                } Else {
                    [System.IO.File]::Delete($Item.FullName);
                    Break;
                }
            }
            default {
                Write-Error "$Item is not a reparse point."
            }
        }
    }    
}
Posted by silent__thought on 6/7/2012 at 1:26 PM
Here is a PowerShell module that has wrapper functions for MKLINK. https://gist.github.com/2891103
Posted by Bartek Bielawski on 4/30/2011 at 2:15 PM
I can only suggest using wonderful pscx (pscx.codeplex.com) that have few cmdlets to create working with links.