如何使用Python而不使用pywin32来确定Windows上的文件所有者

我正在写一个脚本,需要确定窗口上文件的所有者的用户名。

虽然我发现了一个使用pywin32的解决scheme,但我犹豫不决,因为我不想添加模块依赖。

该脚本将为python 2.6编写,并且必须在32位和64位平台上运行。

我想知道是否有不同的方法,可能与ctypes,来确定这个信息

下面的示例使用ctypes访问问题中链接的代码段中的WinAPI函数。

ctypes的定义

import ctypes as ctypes from ctypes import wintypes as wintypes advapi32 = ctypes.WinDLL('advapi32', use_last_error=True) # required constants ERROR_INSUFFICIENT_BUFFER = 0x007A OWNER_SECURITY_INFORMATION = 0x00000001 # related constants ERROR_INVALID_FUNCTION = 0x0001 ERROR_FILE_NOT_FOUND = 0x0002 ERROR_PATH_NOT_FOUND = 0x0003 ERROR_ACCESS_DENIED = 0x0005 GROUP_SECURITY_INFORMATION = 0x00000002 DACL_SECURITY_INFORMATION = 0x00000004 SACL_SECURITY_INFORMATION = 0x00000008 LABEL_SECURITY_INFORMATION = 0x00000010 ATTRIBUTE_SECURITY_INFORMATION = 0x00000020 SCOPE_SECURITY_INFORMATION = 0x00000040 BACKUP_SECURITY_INFORMATION = 0x00010000 UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000 PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000 PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 # type definitions LPBOOL = ctypes.POINTER(wintypes.BOOL) LPDWORD = ctypes.POINTER(wintypes.DWORD) PSID = ctypes.POINTER(wintypes.BYTE) PSECURITY_DESCRIPTOR = ctypes.POINTER(wintypes.BYTE) SECURITY_INFORMATION = wintypes.DWORD class SID_NAME_USE(wintypes.DWORD): _sid_types = dict(enumerate(''' User Group Domain Alias WellKnownGroup DeletedAccount Invalid Unknown Computer Label'''.split(), 1)) def __init__(self, value=None): if value is not None: if value not in self.sid_types: raise ValueError('invalid SID type') wintypes.DWORD.__init__(value) def __str__(self): if self.value not in self._sid_types: raise ValueError('invalid SID type') return self._sid_types[self.value] PSID_NAME_USE = ctypes.POINTER(SID_NAME_USE) # function pointer prototypes def _check_bool(result, func, args, WinError=ctypes.WinError, get_last_error=ctypes.get_last_error): if not result: raise WinError(get_last_error()) return args # msdn.microsoft.com/en-us/library/aa446639 advapi32.GetFileSecurityW.errcheck = _check_bool advapi32.GetFileSecurityW.argtypes = ( wintypes.LPCWSTR, # _In_ lpFileName SECURITY_INFORMATION, # _In_ RequestedInformationRequested PSECURITY_DESCRIPTOR, # _Out_opt_ pSecurityDescriptor wintypes.DWORD, # _In_ nLength LPDWORD) # _Out_ lpnLengthNeeded # msdn.microsoft.com/en-us/library/aa446651 advapi32.GetSecurityDescriptorOwner.errcheck = _check_bool advapi32.GetSecurityDescriptorOwner.argtypes = ( PSECURITY_DESCRIPTOR, # _In_ pSecurityDescriptor ctypes.POINTER(PSID), # _Out_ pOwner LPBOOL) # _Out_ lpbOwnerDefaulted # msdn.microsoft.com/en-us/library/aa379166 advapi32.LookupAccountSidW.errcheck = _check_bool advapi32.LookupAccountSidW.argtypes = ( wintypes.LPCWSTR, # _In_opt_ lpSystemName PSID, # _In_ lpSid wintypes.LPCWSTR, # _Out_opt_ lpName LPDWORD, # _Inout_ cchName wintypes.LPCWSTR, # _Out_opt_ lpReferencedDomainName LPDWORD, # _Inout_ cchReferencedDomainName PSID_NAME_USE) # _Out_ peUse 

函数定义

 def get_file_security(filename, request): length = wintypes.DWORD() # NB This query may fail with ERROR_INVALID_FUNCTION # for some filesystems. try: advapi32.GetFileSecurityW(filename, request, None, 0, ctypes.byref(length)) except WindowsError as e: if e.winerror != ERROR_INSUFFICIENT_BUFFER: raise if not length.value: return None sd = (wintypes.BYTE * length.value)() advapi32.GetFileSecurityW(filename, request, sd, length, ctypes.byref(length)) return sd def look_up_account_sid(sid): SIZE = 256 name = ctypes.create_unicode_buffer(SIZE) domain = ctypes.create_unicode_buffer(SIZE) cch_name = wintypes.DWORD(SIZE) cch_domain = wintypes.DWORD(SIZE) sid_type = SID_NAME_USE() advapi32.LookupAccountSidW(None, sid, name, ctypes.byref(cch_name), domain, ctypes.byref(cch_domain), ctypes.byref(sid_type)) return name.value, domain.value, sid_type def get_file_owner(filename): sd = get_file_security(filename, OWNER_SECURITY_INFORMATION) sid = PSID() sid_defaulted = wintypes.BOOL() advapi32.GetSecurityDescriptorOwner(sd, ctypes.byref(sid), ctypes.byref(sid_defaulted)) name, domain, sid_type = look_up_account_sid(sid) return name, domain, sid_type 

示例脚本

 if __name__ == '__main__': import sys filename = sys.argv[1] if isinstance(filename, bytes): filename = filename.decode('mbcs') name, domain, sid_type = get_file_owner(filename) if domain: name = '{0}\\{1}'.format(domain, name) print("File : {0}".format(filename)) print("Owner: {0} ({1})".format(name, sid_type)) 

演示

 C:\>get_file_owner.py C:\Windows File : C:\Windows Owner: NT SERVICE\TrustedInstaller (WellKnownGroup) C:\>get_file_owner.py C:\Users File : C:\Users Owner: NT AUTHORITY\SYSTEM (WellKnownGroup) 

你可以调用一个windows shell命令“dir / q”并解析输出以找到所有者。

 subprocess.call("dir /q", shell=True)