Getting "Access is denied" when moving a folder to a symlink which is pointing to another drive

I have a drive named D and a drive named E. I created a folder named "test" in drive D and a folder named "destination" in drive E using the mkdir command. Then in D I created a symlink using the following command:

mklink /D D:\source E:\destination

Now, when I try to move the folder named "test" from D to D:\source using the command move D:\test D:\source, I get an error message simply saying "Access is denied". If I try to move a file named "test.txt" with the command move D:\test.txt D:\source, I get no error and the file is moved to E:\destination successfully.

I also tried to do this in powershell with the command mv D:\test\ D:\source\ and got the same result but I got a longer error message which reads:

mv : Access to the path 'D:\test\' is denied.
At line:1 char:1
+ mv D:\test\ D:\source\
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (D:\test\:DirectoryInfo) [Move-Item], IOException
    + FullyQualifiedErrorId : MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand

Interestingly, I just noticed that moving the test folder directly to the destination folder using move D:\test E:\destination also triggers the "Access is denied" error. So my problem might not relate specifically to symlink. However moving the folder in powershell with move D:\test E:\destination works fine (whereas it was failing when it was a symlink). It's very strange.

Why am I getting this access denied error and why does it only return an error if I try to move a folder and not a file? Also why does directly moving the folder fail in cmd but succeeds in powershell? Is there anything I can do to circumvent the error?

Note: I tried all the commands as Administrator.

Here is the security tab of the destination folder's properties:

security tab of destination folder's properties

And here is the security tab of the test folder's properties:

security tab of test folder's properties


An interesting issue which got me thinking. @harrymc is right. This does not have to do with permissions.

There is a difference where you use move at cmd.exe or PowerShell

move command at cmd.exe is different program than move from PowerShell. Move at PowerShell is actually only an alias for Move-Item whereas move is an internal cmd.exe command. See below Notes for the difference!

The issue

This issue will be the same for symbolic links or Junctions (for more on the differences see directory-junction-vs-directory-symbolic-link).

The issue is that the internal function of move (cmd.exe) and Move-Item (PowerShell) can't handle the drive volume change. In essence it is same as Move-Item the regression for PowerShell 7.2. The core of the issue is that the function MoveTo() can not handle the drive volume change (on the symlink) and there has to be a fallback to CopyAndDelete() function.

The solution

@cmd.exe

The solution for cmd.exe is to use robocopy (c:\Windows\System32\Robocopy.exe). The robocopy depreciates xcopy at Windows 10. xcopy could also be used, but will be probably removed in the future so the examples are for robocopy only.

An example:

To move a directory to a symbolic link dir:

a) robocopy d:\test d:\destination /E /MOVE

/E : Copy Subfolders, including Empty Subfolders.

/MOVE : Move files and dirs (delete from source after copying).

Please note a feature: that if the directory d:\test is empty it won't be moved but it will get deleted.

b) robocopy d:\test d:\destination /S /MOV

/S : Copy Subfolders. /MOV : MOVe files (delete from source after copying).

Copies non-empty subfolders and removes files only after copying.

@PowerShell

You could use the robocopy.exe here too, but if you want to do it natively for all PowerShell versions, you have to use copy&delete (similar to the "fix" above when there is a fall back for drive volume change on symlink).

Here it is on one line:

Copy-Item -Path d:\test -Destination d:\destination; Delete-Item -Path d:\test

Note: Should you have issue with Delete-Item you can try to use the -Force switch.

I'm using PowerShell 5.1.18362.1801 the moving of directory regression will be probably fixed in later versions.

Notes

PowerShell move

NAME
    Move-Item

SYNTAX
    Move-Item [-Path] <string[]> [[-Destination] <string>] [-Force] [-Filter <string>] [-Include <string[]>] [-Exclude <string[]>
    ] [-PassThru] [-Credential <pscredential>] [-WhatIf] [-Confirm] [-UseTransaction]  [<CommonParameters>]

    Move-Item [[-Destination] <string>] -LiteralPath <string[]> [-Force] [-Filter <string>] [-Include <string[]>] [-Exclude <stri
    ng[]>] [-PassThru] [-Credential <pscredential>] [-WhatIf] [-Confirm] [-UseTransaction]  [<CommonParameters>]


ALIASES
    mi
    mv
    move


REMARKS
    Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
        -- To download and install Help files for the module that includes this cmdlet, use Update-Help.
        -- To view the Help topic for this cmdlet online, type: "Get-Help Move-Item -Online" or
           go to https://go.microsoft.com/fwlink/?LinkID=113350.

cmd.exe move:

move /?
Moves files and renames files and directories.

To move one or more files:
MOVE [/Y | /-Y] [drive:][path]filename1[,...] destination

To rename a directory:
MOVE [/Y | /-Y] [drive:][path]dirname1 dirname2

  [drive:][path]filename1 Specifies the location and name of the file
                          or files you want to move.
  destination             Specifies the new location of the file. Destination
                          can consist of a drive letter and colon, a
                          directory name, or a combination. If you are moving
                          only one file, you can also include a filename if
                          you want to rename the file when you move it.
  [drive:][path]dirname1  Specifies the directory you want to rename.
  dirname2                Specifies the new name of the directory.

  /Y                      Suppresses prompting to confirm you want to
                          overwrite an existing destination file.
  /-Y                     Causes prompting to confirm you want to overwrite
                          an existing destination file.

The switch /Y may be present in the COPYCMD environment variable.
This may be overridden with /-Y on the command line.  Default is
to prompt on overwrites unless MOVE command is being executed from
within a batch script.