I'm trying to use the CreateSymbolicLinkW() function (from Kernel32.dll) to create a symlink.
On the respective machine (Win7 Pro x64 SP1):
- UAC is enabled (=processes of users with local admin privileges are by default NOT elevated)
- I've granted all authenticated users the "create symbolic link" user rights assignment (through a group policy with Computer -> Windows Settings -> Security -> Local Policies -> User Rights Assignment -> Create Symbolic Link = Authenticated Users)
- I've enabled all possible symlink evaluation types (again through a Group Policy setting). (to confirm "fsutil behavior query SymlinkEvaluation" returns: "Local to local symbolic links are enabled. Local to remote symbolic links are enabled. Remote to local symbolic links are enabled. Remote to remote symbolic links are enabled."
the Situation now is:
- when I run CreateSymbolicLinkW() as a NON-ADMIN user in an UNELEVATED process, it WORKS (symlink created)
- when I run CreateSymbolicLinkW() as an ADMIN user in a ELEVATED process, it WORKS (symlink created)
- when I run CreateSymbolicLinkW() as an ADMIN (!) user in a UNELEVATED (!) process, it DOES NOT WORK
The last case is the actual problem. The error returned by GetLastError is: 1314 (= "a required privilege is not held by the client").
Why is it failing for the Admin user in an unelevated process, while it works for any non-admin user in an unelevated shell?
My code is intended to be run by any type of user, preferably in an unelevated process. Asking admin users to elevate the process as a workaround is something that I'd like to avoid at any circumstance.
The same behavior can also be reproduced with the MKLINK command in the Windows shell btw (fails for admin users in a non-elevated shell while it works for all non-admin users in a non-elevated shell).
Sample Code with Python 2.7:
import ctypes
CreateSymbolicLinkW = ctypes.WinDLL("Kernel32").CreateSymbolicLinkW
CreateSymbolicLinkW(u"c:\\linktest\\testlink.txt", u"c:\\linktest\\testtarget.txt",0)
print(ctypes.WinDLL("Kernel32").GetLastError())