Windows中pwd.getpwnam(username).pw_dir的等价物是什么?

8 投票
4 回答
7776 浏览
提问于 2025-04-16 01:40

Python的pwd模块可以让我们使用getpwnam(3)这个POSIX API,来通过用户名获取某个用户的主目录,同时也能检查这个用户名是否有效。如果你用一个不存在的用户名去调用pwd.getpwnam,程序会报错。

乍一看,我们似乎可以通过os.path.expanduser('~username')在不同平台上也得到相同的结果。不过,在Windows XP上使用Python 2.6时,如果用户名不存在,这个方法不会报错。而在Windows XP上使用Python 2.5时,即使是有效的用户名,这个方法也可能会出错。

那么,在Windows上,我们能否可靠地获取这些信息呢?怎么做呢?

4 个回答

0

你可以使用 win32api.GetUserName() 这个方法来获取当前用户的名字,或者使用 win32net.NetUserGetInfo() 这个方法来获取任何用户的信息,包括本地用户。不过,后者可能会比较慢,因为它需要一些时间从操作系统获取这些信息。

  import win32net

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

另外,你也可以在Windows上查看环境变量 USERPROFILE,或者在Unix系统上查看 HOME,这样也能得到当前登录用户的信息:

  def userDir():
      if os.platform.system() == 'Windows':
          return os.environ['USERPROFILE']
      elif os.platform.system() == 'Linux':
          return os.environ['HOME'] 
      else:
          return None
3

我刚接触Windows安全方面的内容……通过阅读MSDN和一些博客,我发现微软希望我们处理其他用户特定数据的方式是通过获取用户令牌。

以前有一个很不错的维基,叫做Keith Brown的.Net开发者Windows安全指南……你现在可以在Google缓存中找到它,搜索“pluralsight keith.guidebook”。

情况1:如果你没有用户密码:

对于本地账户,你可以尝试读取Windows注册表,正如Nas Banov已经建议的那样,网上还有其他一些方法。

我不太确定不同版本的Windows在新创建的用户方面表现如何……那些从未进行过交互式登录的用户……系统会自动为他们创建注册表、主文件夹和个人资料数据吗?我在Windows XP上做了一些测试,发现创建本地账户后这些注册表键并不存在……但在这种情况下,你可以尝试根据所有用户的注册表值来猜测……或者就失败吧 :)

对于桌面应用程序,当应用程序以已登录用户的身份运行时,我使用类似下面的方式来获取主文件夹……而要获取相当于~/.local的内容,我使用CSIDL_APPDATA,适用于漫游配置文件,或者直接使用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)

阅读Keith Brown的文章“如何获取用户令牌”……你可以寻找一些其他获取用户令牌而不需要密码的方法……

情况2:如果你有用户密码:

根据我在MSDN上的阅读,如果我有用户令牌,我可以通过调用类似下面的代码来获取他们的文件夹……但对我来说并没有成功。(不太确定原因)

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)

这就是我最终写出这段代码的原因……这段代码远非完美,因为它需要用户名和密码。

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()

这个问题有点相关:如何使用Python找到真实的用户主目录?

4

阅读2.6版本的文档可以发现,os.path.expanduser()在Windows系统上有问题:

在Windows上,如果设置了HOME和USERPROFILE环境变量,就会使用这两个变量;如果没有设置,就会用HOMEPATH和HOMEDRIVE的组合。对于以~user开头的路径,它会通过去掉上面生成的用户路径中的最后一个目录来处理。

这是什么情况?这假设所有用户的家目录都必须在同一个父目录下。才不是呢!

虽然找这个解决方案有点困难,但这里有一个可以根据给定的名字查找本地用户的办法:

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]

撰写回答