3

Since the windows 10 creator update, you can enable developer mode to circumvent administrator privileges when creating a symlink. Now, I was able to create a symlink using mklink like this:

os.system('mklink %s %s' %(dst, src))

Hopefully it's obvious that dst is the destination symlink path, and src is the source file for the symlink. While it seems to work ok, it doesn't error if it fails which makes it a little more difficult to ensure each symlink is successful. I can check if the path exists after each symlink, but that's less efficient than a try/except clause. There's also what looks like a command shell window(?) that pops up and closes quickly every time - and that's really annoying when you're symlinking a lot of files...

So, I've been trying other options I've found on stack overflow like this one: How to create symlinks in windows using Python? Unfortunately, the CreateSymbolicLinkW command doesn't seem to work for me... I also found this: OS.symlink support in windows where it appears you need to adjust the group policy editor; however, it apparently still requires users in the administrator group to run the process as an administrator even if you explicitly set that user with symlink privileges.

With the windows 10 creator update, there's mention of a new dwflag in the CreateSymbolicLink api (SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) you can see the reference for that here: symlinks windows 10

Using the ctypes stuff is a bit over my head, so I'm wondering if anyone knows: Can I actually use that new dwflag? How do I use it? Will it work without running the process as administrator?

I use Autodesk Maya, so I'm stuck with python 2.7 options... I have not tried launching Maya as an administrator so I don't know if that will work, but it seems like a rather annoying hoop to jump through even if it does... I appreciate any assistance you can give

silent_sight
  • 492
  • 1
  • 8
  • 16
  • `os.symlink` doesn't support `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE` yet. But this function isn't available on Windows in Python 2 anyway. If you have PyWin32 available, you can call [`win32file.CreateSymbolicLink`](http://docs.activestate.com/activepython/2.6/pywin32/win32file__CreateSymbolicLink_meth.html) and manually pass in the flag value (2). Remember to indicate when the target is a directory (1), in which case `Flags` needs both values, e.g. `2 | 1`. – Eryk Sun Jun 06 '17 at 01:22
  • I do not have access to pywin32 at this point... I was unsuccessfully trying to use the flag in this `kdll = ctypes.windll.LoadLibrary("kernel32.dll"); kdll.CreateSymbolicLinkW(dst, src, 2) ` Sorry for the bad formatting... could not figure out how to drop those two lines down so they each got their own line – silent_sight Jun 06 '17 at 19:06
  • Use `kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)`. Then if a call fails, you can raise an accurate exception via `raise ctypes.WinError(ctypes.get_last_error())`. – Eryk Sun Jun 06 '17 at 23:07

2 Answers2

3

it doesn't error if it fails

os.system will return the exit status of the call. It does not raise an exception.

If you look at the docs for os.system, they recommend using the subprocess module. In fact, subprocess.check_call does what you describe (raise an exception on a non-zero exit status). Perhaps that would work better.

On the other hand, the command mklink will return a zero exit status even if the source does not exist (it will create a link to non-existent file and return 0). You might want to validate the actual link as you mentioned, depending on what errors you are trying to find.

As far as hiding the console window, see this.

Wyrmwood
  • 3,340
  • 29
  • 33
  • 1
    With subprocess, you'll need `shell=True` to run `mklink` since it's an internal shell command. `shell=True` automatically hides the console window. – Eryk Sun Jun 06 '17 at 01:25
  • I needed not only `shell=True`, but also had to open an elevated command prompt, for python or the shell, otherwise I got `FileNotFoundError: [WinError 2] The system cannot find the file specified` from python and `You do not have sufficient privilege to perform this operation.` from the shell. – Wyrmwood Jun 06 '17 at 14:53
  • `subprocess.check_call('mklink %s %s' %(dst, src), shell=True)` worked out great! Fortunately, with developer mode enabled, I did not get a privileges error like Wyrmwood did. And `shell=True` did suppress the console window popping up. – silent_sight Jun 06 '17 at 18:50
1

os.symlink works out of the box since python 3.8 on windows, as long as Developer Mode is turned on.

Not sure whether this will help with Maya; they seem to have committed to Python 3 though.

BlackShift
  • 2,296
  • 2
  • 19
  • 27