What is the Windows equivalent of pwd.getpwnam(username).pw_dir?

馋奶兔 提交于 2019-12-09 16:11:25

问题


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?


回答1:


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]



回答2:


I am new to Windows security... but reading MSDN and some blogs it seems to me that the way MS want us to handle other users specific data is by getting a user token.

There used to be a nice wiki of Keith Brown .Net Developers Guide to Windows Security... you can still find it in Google cache for "pluralsight keith.guidebook"

Case 1: If you don't have the user password:

For local accounts you can try reading the Windows registry as Nas Banov already suggested and there are some other recipes on SO or the Internet.

I am not sure how various Windows versions behaves for freshly create users ... those which have never performed an interactive session login ... does it automatically creates their registry, home folder and profile data? I have done some tests on Windows XP and those registry keys were not present after creating an local account ... but in this case you can try to guess it based in All Users registry values ... or just fail :)

For desktop applications, when the application is running as a logged in user, I am using something like this to get the home folder.... and to get the equivalent of ~/.local I am using CSIDL_APPDATA, for roaming profiles, or just CSIDL_LOCAL_APPDATA.

from win32com.shell import shell, shellcon
# See microsoft references for further CSIDL constants
# http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
folder_name = shell.SHGetFolderPath(0, shellcon.CSIDL_PROFILE, 0, 0)

Reading Keith Brown article "How To Get A Token For A User" .. you can look for some other ways of getting an user token without a password...

Case 2: If you have the user password:

Reading the MSDN I got the impressing that if I have an user token, I can get its folders by calling something like the code below... but it did not worked for me. (not sure why)

token = win32security.LogonUser(
            username,
            None, # we uses UPN format for username
            password,
            win32security.LOGON32_LOGON_NETWORK,
            win32security.LOGON32_PROVIDER_DEFAULT,
            )
folder_name = shell.SHGetFolderPath(0, shellcon.CSIDL_PROFILE, token, 0)

This is why I ended up with this code...which is far from being perfect due to the fact that it requires username and password.

token = win32security.LogonUser(
            username,
            None, # Here should be the domain ... or just go with default values
            password,
            win32security.LOGON32_LOGON_NETWORK,
            win32security.LOGON32_PROVIDER_DEFAULT,
            )
win32security.ImpersonateLoggedOnUser(token)
folder_name = shell.SHGetFolderPath(0, shellcon.CSIDL_PROFILE, 0, 0)
win32security.RevertToSelf()

This question is somehow related: How to find the real user home directory using python?




回答3:


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



回答4:


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



来源:https://stackoverflow.com/questions/3305787/what-is-the-windows-equivalent-of-pwd-getpwnamusername-pw-dir

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!