views:

141

answers:

3

The Python pwd module provides access to getpwnam(3) POSIX API, which can be used to get the home directory for a particular user by username, as well determining if the username is valid at all. pwd.getpwnam will raise an exception if called with a non-existent username.

At first it seems like the same result can be achieved in a cross-platform manner via os.path.expanduser('~username'). However, it appears that with Python 2.6 on Windows XP this won't actually produce a failure for a non-existent username. Furthermore, on Python 2.5 on Windows XP, it seems to fail even for valid users.

Can this information be obtained reliably on Windows? How?

A: 

you could go the win32api.GetUserName() (current user only) or win32net.NetUserGetInfo() (any user on any server, localhost included) route. the latter could be a bit slow since it can take some time to get this information back from the OS.

  import win32net

  def userDir(username):
        return win32net.NetUserGetInfo(None, username, 1).get("home_dir")

alternatively you could expand the environment variable USERPROFILE on windows or HOME on unix to get the information about the currently logged in user:

  def userDir():
      if os.platform.system() == 'Windows':
          return os.environ['USERPROFILE']
      elif os.platform.system() == 'Linux':
          return os.environ['HOME'] 
      else:
          return None
akira
Won't work - this will return info only for the *current* user. The question is about *any*, 'particular' user.
Nas Banov
@Nas Banov: true, but only for the 2nd part of my answer. win32api.NetUserGetInfo () retrieves the information for ANY user.
akira
@Akira: Sounds nice but how? `win32net.NetUserGetInfo(None, userName, 4))` returns `'home_dir': u''`, i.e. useless
Nas Banov
@Nas Banov: yes. interesting, isn't it? could be a Windows7 issue?
akira
@Akira: I doubt issue is win7 related, since i tested on XP. Probably need to RTFM for gory details
Nas Banov
some comments i ve seen online "suggest", that "home_dir" is empty if it is set to the default... still unclear.
akira
+2  A: 

Reading the 2.6 documentation shows that os.path.expanduser() is broken on Windows:

On Windows, HOME and USERPROFILE will be used if set, otherwise a combination of HOMEPATH and HOMEDRIVE will be used. An initial ~user is handled by stripping the last directory component from the created user path derived above.

Say whaat? This assumes all user homes have to be under the same parent directory. Nuh-ugh!

It was a bit hard to dig but here is a solution that will look up a local user by given name:

from win32security import LookupAccountName, ConvertSidToStringSid
from _winreg import OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE

def getUserDir(userName):
    ssid = ConvertSidToStringSid(LookupAccountName(None, userName)[0])
    key = OpenKey(HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\\' + ssid)
    return QueryValueEx(key, 'ProfileImagePath')[0]
Nas Banov
@Nas Banov: this yields results only for local users?
akira
just to make it clear.
akira
This getUserDir looks promising. I tried it out on my problem but unfortunately immediately ran into a problem where my code is running as a service which apparently isn't mapped to a user (somehow), so one of the calls failed (with an exception complaining about the lack of such a mapping). For the time being I stopped there, but I'll probably revisit this at some point. Perhaps once I set up whatever mapping is required, this function will satisfy the requirements.
Jean-Paul Calderone
@Jean-Paul: ah, this seems entirely another issue. By default win services run under _"built-in security principal"_ `LocalService`, which is sort of a user but may have some limitations (no NetBEUI, no GUI). Optionally you can choose to run a service under another, particular user login. E.g. PostgreSQL runs its daemon under user "postgres".
Nas Banov
@Jean-Paul: ps. care to select best answer? :)
Nas Banov
A: 

This seems to be only applicable to the current user, but on my (winxp) machine, os.path.expanduser('~') returns my home directory.

Wayne Werner