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:
And here is the security tab of the 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.