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
[email protected]
http://mail.python.org/mailman/listinfo/python-win32