hi, windows-xp/7 python-2.6.2 pywin32-217
ages ago i wrote some code to get a user's home directory on windows (even if they'd gone into the registry and moved it). i remember it working when i wrote it but at some point it stopped working. when i looked into it, it turned out that the registry subkeys no longer looked like what the code was expecting. the code was something like: import win32api, win32net, win32netcon, win32security, _winreg, re, os def user(): try: dc = win32net.NetServerEnum(None, 100, win32netcon.SV_TYPE_DOMAIN_CTRL) dcname = r'\\' + dc[0][0]['name'] if dc[0] and isinstance(dc[0][0], dict) else None except Exception: dcname = None return win32net.NetUserGetInfo(dcname, win32api.GetUserName(), 1)['name'] def home(username=None): if username is None: username = user() sid = win32security.ConvertSidToStringSid(win32security.LookupAccountName(None, username)[0]) subkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\' + sid key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) val, typ = _winreg.QueryValueEx(key, 'ProfileImagePath') if typ == _winreg.REG_EXPAND_SZ: # Which it is while True: match = re.compile('%\w+%').search(val) if match is None: break varname = val[match.start()+1:match.end()-1] val = val[0:match.start()] + os.getenv(varname, '') + val[match.end():] return val given the account sid: S-1-5-5-21-725345543-1957994488-859522115 it expected to find this registry key: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-5-21-725345543-1957994488-859522115 inside which it expected to find: ProfileImagePath = %SystemDrive%\Documents and Settings\patricia (WindowsXP) ProfileImagePath = C:\Users\patricia (Windows7) however, instead of the above registry key, there are: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-5-21-725345543-1957994488-859522115-1003 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-5-21-725345543-1957994488-859522115-1004 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-5-21-725345543-1957994488-859522115-1005 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-5-21-725345543-1957994488-859522115-1006 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-5-21-725345543-1957994488-859522115-1008 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-5-21-725345543-1957994488-859522115-1009 each referring to a different user (patricia happens to be the one ending in 1009). sadly, i've resorted to poking around likely locations in the file system but that's not very satisfying. and i'd like to avoid enumerating through all of these keys and just assuming that the home directory contains the user's login name (even though that's very likely). so my questions are: did the sid for the account name ever uniquely identify the user? how do i obtain the "1009" that needs to be appended to the sid to complete it? i've attached the real code in case it's of any help. p.s. i know (as of a few minutes ago) that there is a win32profile module that looks like it should do all of this for me but according to its documentation, i can only use win32profile.GetUserProfileDirectory() if i have a token returned by win32security.LogonUser() but i don't want or need to log the user in (even if i knew their passwords!) so i have no such token and i can't use that function. cheers, raf
#!/usr/bin/env python '''This module provides functions for obtaining the current user's name and any user's home directory. They don't rely on environment variables and they work properly on both POSIX and Windows systems. Actually, finding the home directory doesn't work properly on Windows. It gets the ProfileImagePath out of the registry but this is not the same as the home directory in local users and groups. So, if the user has specified a non-default home directory, this won't find it. It will find the default one instead. Also, the registry structure seems to have changed so that no longer works anymore and instead we poke around the file system looking for a likely candidate. I wish Windows would stop moving my chair.''' import os, re _debug = 0 _has_domain_controller = 0 def set_has_dc(has_domain_controller=1): '''Tell this module to look for a windows domain controller. Don't do this unless there is a domain controller because sometimes it causes inordinately long and unnecessary delays.''' global _has_domain_controller _has_domain_controller = has_domain_controller def user(): '''Return the user name of the current user.''' try: return _user_mswin() except ImportError: try: return _user_posix() except Exception: return '' def _user_posix(): '''Return the name of the current user on POSIX systems. Called by user().''' import pwd return pwd.getpwuid(os.getuid())[0] def _user_mswin(): '''Return the name of the current user on Windows systems. Called by user().''' import win32api, win32net, win32netcon if _has_domain_controller: try: dc = win32net.NetServerEnum(None, 100, win32netcon.SV_TYPE_DOMAIN_CTRL) dcname = r'\\' + dc[0][0]['name'] if dc[0] and isinstance(dc[0][0], dict) else None except Exception, e: if _debug: import traceback print('debug: Error: %s\n%s' % (e, traceback.format_exc())) dcname = None else: dcname = None user = win32api.GetUserName() return win32net.NetUserGetInfo(dcname, user, 1)['name'] def home(username=None): '''Return the home directory of the current user or the given user.''' try: return _home_mswin(username) except ImportError, e: try: return _home_posix(username) except Exception: return os.curdir def _home_posix(username=None): '''Return the home directory of the current user or the given user on POSIX systems. Called by home().''' if not username: username = _user_posix() import pwd return pwd.getpwnam(username)[5] def _home_mswin(username=None): '''Return the home directory of the current user or the given user on Windows systems. Called by home().''' if username is None: username = _user_mswin() import _winreg, win32security acct = win32security.LookupAccountName(None, username) if _debug: print('debug: acct = %r' % (acct,)) sid = acct[0] if _debug: print('debug: sid = %r' % sid) #sid = win32security.ConvertSidToStringSid(win32security.LookupAccountName(None, username)[0]) sid = win32security.ConvertSidToStringSid(sid) subkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\' + sid if _debug: print('debug: sid = %r' % sid) print('debug: subkey = %r' % subkey) try: key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) except WindowsError, e: if _debug: import traceback print('debug: Error: %s\n%s' % (e, traceback.format_exc())) # XXX The above no longer works. There are registry entries that look # XXX like subkey-#### but none that look like subkey. It looks like # XXX the sid is not complete. val = 'C:/Users/' + username if os.path.exists(val): return val val = 'C:/Documents and Settings/' + username if os.path.exists(val): return val return os.curdir() val, typ = _winreg.QueryValueEx(key, 'ProfileImagePath') if _debug: print('debug: val = %r' % val) print('debug: typ = %r' % typ) if typ == _winreg.REG_EXPAND_SZ: # Which it is while True: _ = re.compile('%\w+%').search(val) if not _: break varname = val[_.start()+1:_.end()-1] val = val[0:_.start()] + os.getenv(varname, '') + val[_.end():] if _debug: print('debug: val = %r' % val) else: if _debug: print('debug: typ unexpected (!= %s)' % _winreg.REG_EXPAND_SZ) return val if __name__ == '__main__': import test as unittest class Test(unittest.TestCase): def test_set_has_dc(self): set_has_dc() self.eq(_has_domain_controller, 1) set_has_dc(0) self.eq(_has_domain_controller, 0) set_has_dc(1) self.eq(_has_domain_controller, 1) set_has_dc(0) self.eq(_has_domain_controller, 0) def test_user_1(self): u = user() print('user=%r' % u) self.eq(len(u) != 0, True) def test_user_2(self): set_has_dc() u = user() set_has_dc(0) self.eq(len(u) != 0, True) def test_home_1(self): h = home() print('home=%r' % h) self.eq(len(h) != 0, True) self.eq(os.path.isdir(h), True) def test_home_2(self): h = home(user()) self.eq(len(h) != 0, True) self.eq(os.path.isdir(h), True) unittest.main() # vi:set ts=4 sw=4:
_______________________________________________ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32