first commit

This commit is contained in:
Ayxan
2022-05-23 00:16:32 +04:00
commit d660f2a4ca
24786 changed files with 4428337 additions and 0 deletions

View File

@ -0,0 +1,121 @@
import win32com
import win32com.client
if type(__path__) == type(""):
# For freeze to work!
import sys
try:
import adsi
sys.modules["win32com.adsi.adsi"] = adsi
except ImportError:
pass
else:
# See if we have a special directory for the binaries (for developers)
win32com.__PackageSupportBuildPath__(__path__)
# Some helpers
# We want to _look_ like the ADSI module, but provide some additional
# helpers.
# Of specific note - most of the interfaces supported by ADSI
# derive from IDispatch - thus, you get the custome methods from the
# interface, as well as via IDispatch.
import pythoncom
from .adsi import *
LCID = 0
IDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
IADsContainerType = pythoncom.TypeIIDs[adsi.IID_IADsContainer]
def _get_good_ret(
ob,
# Named arguments used internally
resultCLSID=None,
):
assert resultCLSID is None, "Now have type info for ADSI objects - fix me!"
# See if the object supports IDispatch
if hasattr(ob, "Invoke"):
import win32com.client.dynamic
name = "Dispatch wrapper around %r" % ob
return win32com.client.dynamic.Dispatch(ob, name, ADSIDispatch)
return ob
class ADSIEnumerator:
def __init__(self, ob):
# Query the object for the container interface.
self._cont_ = ob.QueryInterface(IID_IADsContainer)
self._oleobj_ = ADsBuildEnumerator(self._cont_) # a PyIADsEnumVARIANT
self.index = -1
def __getitem__(self, index):
return self.__GetIndex(index)
def __call__(self, index):
return self.__GetIndex(index)
def __GetIndex(self, index):
if type(index) != type(0):
raise TypeError("Only integer indexes are supported for enumerators")
if index != self.index + 1:
# Index requested out of sequence.
raise ValueError("You must index this object sequentially")
self.index = index
result = ADsEnumerateNext(self._oleobj_, 1)
if len(result):
return _get_good_ret(result[0])
# Failed - reset for next time around.
self.index = -1
self._oleobj_ = ADsBuildEnumerator(self._cont_) # a PyIADsEnumVARIANT
raise IndexError("list index out of range")
class ADSIDispatch(win32com.client.CDispatch):
def _wrap_dispatch_(
self, ob, userName=None, returnCLSID=None, UnicodeToString=None
):
assert UnicodeToString is None, "this is deprectated and will be removed"
if not userName:
userName = "ADSI-object"
olerepr = win32com.client.dynamic.MakeOleRepr(ob, None, None)
return ADSIDispatch(ob, olerepr, userName)
def _NewEnum(self):
try:
return ADSIEnumerator(self)
except pythoncom.com_error:
# doesnt support it - let our base try!
return win32com.client.CDispatch._NewEnum(self)
def __getattr__(self, attr):
try:
return getattr(self._oleobj_, attr)
except AttributeError:
return win32com.client.CDispatch.__getattr__(self, attr)
def QueryInterface(self, iid):
ret = self._oleobj_.QueryInterface(iid)
return _get_good_ret(ret)
# We override the global methods to do the right thing.
_ADsGetObject = ADsGetObject # The one in the .pyd
def ADsGetObject(path, iid=pythoncom.IID_IDispatch):
ret = _ADsGetObject(path, iid)
return _get_good_ret(ret)
_ADsOpenObject = ADsOpenObject
def ADsOpenObject(path, username, password, reserved=0, iid=pythoncom.IID_IDispatch):
ret = _ADsOpenObject(path, username, password, reserved, iid)
return _get_good_ret(ret)

Binary file not shown.

View File

@ -0,0 +1,340 @@
ADS_ATTR_CLEAR = 1
ADS_ATTR_UPDATE = 2
ADS_ATTR_APPEND = 3
ADS_ATTR_DELETE = 4
ADS_EXT_MINEXTDISPID = 1
ADS_EXT_MAXEXTDISPID = 16777215
ADS_EXT_INITCREDENTIALS = 1
ADS_EXT_INITIALIZE_COMPLETE = 2
ADS_SEARCHPREF_ASYNCHRONOUS = 0
ADS_SEARCHPREF_DEREF_ALIASES = 1
ADS_SEARCHPREF_SIZE_LIMIT = 2
ADS_SEARCHPREF_TIME_LIMIT = 3
ADS_SEARCHPREF_ATTRIBTYPES_ONLY = 4
ADS_SEARCHPREF_SEARCH_SCOPE = 5
ADS_SEARCHPREF_TIMEOUT = 6
ADS_SEARCHPREF_PAGESIZE = 7
ADS_SEARCHPREF_PAGED_TIME_LIMIT = 8
ADS_SEARCHPREF_CHASE_REFERRALS = 9
ADS_SEARCHPREF_SORT_ON = 10
ADS_SEARCHPREF_CACHE_RESULTS = 11
ADS_SEARCHPREF_DIRSYNC = 12
ADS_SEARCHPREF_TOMBSTONE = 13
ADS_SCOPE_BASE = 0
ADS_SCOPE_ONELEVEL = 1
ADS_SCOPE_SUBTREE = 2
ADS_SECURE_AUTHENTICATION = 0x1
ADS_USE_ENCRYPTION = 0x2
ADS_USE_SSL = 0x2
ADS_READONLY_SERVER = 0x4
ADS_PROMPT_CREDENTIALS = 0x8
ADS_NO_AUTHENTICATION = 0x10
ADS_FAST_BIND = 0x20
ADS_USE_SIGNING = 0x40
ADS_USE_SEALING = 0x80
ADS_USE_DELEGATION = 0x100
ADS_SERVER_BIND = 0x200
ADSTYPE_INVALID = 0
ADSTYPE_DN_STRING = ADSTYPE_INVALID + 1
ADSTYPE_CASE_EXACT_STRING = ADSTYPE_DN_STRING + 1
ADSTYPE_CASE_IGNORE_STRING = ADSTYPE_CASE_EXACT_STRING + 1
ADSTYPE_PRINTABLE_STRING = ADSTYPE_CASE_IGNORE_STRING + 1
ADSTYPE_NUMERIC_STRING = ADSTYPE_PRINTABLE_STRING + 1
ADSTYPE_BOOLEAN = ADSTYPE_NUMERIC_STRING + 1
ADSTYPE_INTEGER = ADSTYPE_BOOLEAN + 1
ADSTYPE_OCTET_STRING = ADSTYPE_INTEGER + 1
ADSTYPE_UTC_TIME = ADSTYPE_OCTET_STRING + 1
ADSTYPE_LARGE_INTEGER = ADSTYPE_UTC_TIME + 1
ADSTYPE_PROV_SPECIFIC = ADSTYPE_LARGE_INTEGER + 1
ADSTYPE_OBJECT_CLASS = ADSTYPE_PROV_SPECIFIC + 1
ADSTYPE_CASEIGNORE_LIST = ADSTYPE_OBJECT_CLASS + 1
ADSTYPE_OCTET_LIST = ADSTYPE_CASEIGNORE_LIST + 1
ADSTYPE_PATH = ADSTYPE_OCTET_LIST + 1
ADSTYPE_POSTALADDRESS = ADSTYPE_PATH + 1
ADSTYPE_TIMESTAMP = ADSTYPE_POSTALADDRESS + 1
ADSTYPE_BACKLINK = ADSTYPE_TIMESTAMP + 1
ADSTYPE_TYPEDNAME = ADSTYPE_BACKLINK + 1
ADSTYPE_HOLD = ADSTYPE_TYPEDNAME + 1
ADSTYPE_NETADDRESS = ADSTYPE_HOLD + 1
ADSTYPE_REPLICAPOINTER = ADSTYPE_NETADDRESS + 1
ADSTYPE_FAXNUMBER = ADSTYPE_REPLICAPOINTER + 1
ADSTYPE_EMAIL = ADSTYPE_FAXNUMBER + 1
ADSTYPE_NT_SECURITY_DESCRIPTOR = ADSTYPE_EMAIL + 1
ADSTYPE_UNKNOWN = ADSTYPE_NT_SECURITY_DESCRIPTOR + 1
ADSTYPE_DN_WITH_BINARY = ADSTYPE_UNKNOWN + 1
ADSTYPE_DN_WITH_STRING = ADSTYPE_DN_WITH_BINARY + 1
ADS_PROPERTY_CLEAR = 1
ADS_PROPERTY_UPDATE = 2
ADS_PROPERTY_APPEND = 3
ADS_PROPERTY_DELETE = 4
ADS_SYSTEMFLAG_DISALLOW_DELETE = -2147483648
ADS_SYSTEMFLAG_CONFIG_ALLOW_RENAME = 0x40000000
ADS_SYSTEMFLAG_CONFIG_ALLOW_MOVE = 0x20000000
ADS_SYSTEMFLAG_CONFIG_ALLOW_LIMITED_MOVE = 0x10000000
ADS_SYSTEMFLAG_DOMAIN_DISALLOW_RENAME = -2147483648
ADS_SYSTEMFLAG_DOMAIN_DISALLOW_MOVE = 0x4000000
ADS_SYSTEMFLAG_CR_NTDS_NC = 0x1
ADS_SYSTEMFLAG_CR_NTDS_DOMAIN = 0x2
ADS_SYSTEMFLAG_ATTR_NOT_REPLICATED = 0x1
ADS_SYSTEMFLAG_ATTR_IS_CONSTRUCTED = 0x4
ADS_GROUP_TYPE_GLOBAL_GROUP = 0x2
ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = 0x4
ADS_GROUP_TYPE_LOCAL_GROUP = 0x4
ADS_GROUP_TYPE_UNIVERSAL_GROUP = 0x8
ADS_GROUP_TYPE_SECURITY_ENABLED = -2147483648
ADS_UF_SCRIPT = 0x1
ADS_UF_ACCOUNTDISABLE = 0x2
ADS_UF_HOMEDIR_REQUIRED = 0x8
ADS_UF_LOCKOUT = 0x10
ADS_UF_PASSWD_NOTREQD = 0x20
ADS_UF_PASSWD_CANT_CHANGE = 0x40
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x80
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 0x100
ADS_UF_NORMAL_ACCOUNT = 0x200
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 0x800
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0x1000
ADS_UF_SERVER_TRUST_ACCOUNT = 0x2000
ADS_UF_DONT_EXPIRE_PASSWD = 0x10000
ADS_UF_MNS_LOGON_ACCOUNT = 0x20000
ADS_UF_SMARTCARD_REQUIRED = 0x40000
ADS_UF_TRUSTED_FOR_DELEGATION = 0x80000
ADS_UF_NOT_DELEGATED = 0x100000
ADS_UF_USE_DES_KEY_ONLY = 0x200000
ADS_UF_DONT_REQUIRE_PREAUTH = 0x400000
ADS_UF_PASSWORD_EXPIRED = 0x800000
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000
ADS_RIGHT_DELETE = 0x10000
ADS_RIGHT_READ_CONTROL = 0x20000
ADS_RIGHT_WRITE_DAC = 0x40000
ADS_RIGHT_WRITE_OWNER = 0x80000
ADS_RIGHT_SYNCHRONIZE = 0x100000
ADS_RIGHT_ACCESS_SYSTEM_SECURITY = 0x1000000
ADS_RIGHT_GENERIC_READ = -2147483648
ADS_RIGHT_GENERIC_WRITE = 0x40000000
ADS_RIGHT_GENERIC_EXECUTE = 0x20000000
ADS_RIGHT_GENERIC_ALL = 0x10000000
ADS_RIGHT_DS_CREATE_CHILD = 0x1
ADS_RIGHT_DS_DELETE_CHILD = 0x2
ADS_RIGHT_ACTRL_DS_LIST = 0x4
ADS_RIGHT_DS_SELF = 0x8
ADS_RIGHT_DS_READ_PROP = 0x10
ADS_RIGHT_DS_WRITE_PROP = 0x20
ADS_RIGHT_DS_DELETE_TREE = 0x40
ADS_RIGHT_DS_LIST_OBJECT = 0x80
ADS_RIGHT_DS_CONTROL_ACCESS = 0x100
ADS_ACETYPE_ACCESS_ALLOWED = 0
ADS_ACETYPE_ACCESS_DENIED = 0x1
ADS_ACETYPE_SYSTEM_AUDIT = 0x2
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 0x5
ADS_ACETYPE_ACCESS_DENIED_OBJECT = 0x6
ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = 0x7
ADS_ACETYPE_SYSTEM_ALARM_OBJECT = 0x8
ADS_ACETYPE_ACCESS_ALLOWED_CALLBACK = 0x9
ADS_ACETYPE_ACCESS_DENIED_CALLBACK = 0xA
ADS_ACETYPE_ACCESS_ALLOWED_CALLBACK_OBJECT = 0xB
ADS_ACETYPE_ACCESS_DENIED_CALLBACK_OBJECT = 0xC
ADS_ACETYPE_SYSTEM_AUDIT_CALLBACK = 0xD
ADS_ACETYPE_SYSTEM_ALARM_CALLBACK = 0xE
ADS_ACETYPE_SYSTEM_AUDIT_CALLBACK_OBJECT = 0xF
ADS_ACETYPE_SYSTEM_ALARM_CALLBACK_OBJECT = 0x10
ADS_ACEFLAG_INHERIT_ACE = 0x2
ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE = 0x4
ADS_ACEFLAG_INHERIT_ONLY_ACE = 0x8
ADS_ACEFLAG_INHERITED_ACE = 0x10
ADS_ACEFLAG_VALID_INHERIT_FLAGS = 0x1F
ADS_ACEFLAG_SUCCESSFUL_ACCESS = 0x40
ADS_ACEFLAG_FAILED_ACCESS = 0x80
ADS_FLAG_OBJECT_TYPE_PRESENT = 0x1
ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = 0x2
ADS_SD_CONTROL_SE_OWNER_DEFAULTED = 0x1
ADS_SD_CONTROL_SE_GROUP_DEFAULTED = 0x2
ADS_SD_CONTROL_SE_DACL_PRESENT = 0x4
ADS_SD_CONTROL_SE_DACL_DEFAULTED = 0x8
ADS_SD_CONTROL_SE_SACL_PRESENT = 0x10
ADS_SD_CONTROL_SE_SACL_DEFAULTED = 0x20
ADS_SD_CONTROL_SE_DACL_AUTO_INHERIT_REQ = 0x100
ADS_SD_CONTROL_SE_SACL_AUTO_INHERIT_REQ = 0x200
ADS_SD_CONTROL_SE_DACL_AUTO_INHERITED = 0x400
ADS_SD_CONTROL_SE_SACL_AUTO_INHERITED = 0x800
ADS_SD_CONTROL_SE_DACL_PROTECTED = 0x1000
ADS_SD_CONTROL_SE_SACL_PROTECTED = 0x2000
ADS_SD_CONTROL_SE_SELF_RELATIVE = 0x8000
ADS_SD_REVISION_DS = 4
ADS_NAME_TYPE_1779 = 1
ADS_NAME_TYPE_CANONICAL = 2
ADS_NAME_TYPE_NT4 = 3
ADS_NAME_TYPE_DISPLAY = 4
ADS_NAME_TYPE_DOMAIN_SIMPLE = 5
ADS_NAME_TYPE_ENTERPRISE_SIMPLE = 6
ADS_NAME_TYPE_GUID = 7
ADS_NAME_TYPE_UNKNOWN = 8
ADS_NAME_TYPE_USER_PRINCIPAL_NAME = 9
ADS_NAME_TYPE_CANONICAL_EX = 10
ADS_NAME_TYPE_SERVICE_PRINCIPAL_NAME = 11
ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME = 12
ADS_NAME_INITTYPE_DOMAIN = 1
ADS_NAME_INITTYPE_SERVER = 2
ADS_NAME_INITTYPE_GC = 3
ADS_OPTION_SERVERNAME = 0
ADS_OPTION_REFERRALS = ADS_OPTION_SERVERNAME + 1
ADS_OPTION_PAGE_SIZE = ADS_OPTION_REFERRALS + 1
ADS_OPTION_SECURITY_MASK = ADS_OPTION_PAGE_SIZE + 1
ADS_OPTION_MUTUAL_AUTH_STATUS = ADS_OPTION_SECURITY_MASK + 1
ADS_OPTION_QUOTA = ADS_OPTION_MUTUAL_AUTH_STATUS + 1
ADS_OPTION_PASSWORD_PORTNUMBER = ADS_OPTION_QUOTA + 1
ADS_OPTION_PASSWORD_METHOD = ADS_OPTION_PASSWORD_PORTNUMBER + 1
ADS_SECURITY_INFO_OWNER = 0x1
ADS_SECURITY_INFO_GROUP = 0x2
ADS_SECURITY_INFO_DACL = 0x4
ADS_SECURITY_INFO_SACL = 0x8
ADS_SETTYPE_FULL = 1
ADS_SETTYPE_PROVIDER = 2
ADS_SETTYPE_SERVER = 3
ADS_SETTYPE_DN = 4
ADS_FORMAT_WINDOWS = 1
ADS_FORMAT_WINDOWS_NO_SERVER = 2
ADS_FORMAT_WINDOWS_DN = 3
ADS_FORMAT_WINDOWS_PARENT = 4
ADS_FORMAT_X500 = 5
ADS_FORMAT_X500_NO_SERVER = 6
ADS_FORMAT_X500_DN = 7
ADS_FORMAT_X500_PARENT = 8
ADS_FORMAT_SERVER = 9
ADS_FORMAT_PROVIDER = 10
ADS_FORMAT_LEAF = 11
ADS_DISPLAY_FULL = 1
ADS_DISPLAY_VALUE_ONLY = 2
ADS_ESCAPEDMODE_DEFAULT = 1
ADS_ESCAPEDMODE_ON = 2
ADS_ESCAPEDMODE_OFF = 3
ADS_ESCAPEDMODE_OFF_EX = 4
ADS_PATH_FILE = 1
ADS_PATH_FILESHARE = 2
ADS_PATH_REGISTRY = 3
ADS_SD_FORMAT_IID = 1
ADS_SD_FORMAT_RAW = 2
ADS_SD_FORMAT_HEXSTRING = 3
# Generated by h2py from AdsErr.h
def _HRESULT_TYPEDEF_(_sc):
return _sc
E_ADS_BAD_PATHNAME = _HRESULT_TYPEDEF_((-2147463168))
E_ADS_INVALID_DOMAIN_OBJECT = _HRESULT_TYPEDEF_((-2147463167))
E_ADS_INVALID_USER_OBJECT = _HRESULT_TYPEDEF_((-2147463166))
E_ADS_INVALID_COMPUTER_OBJECT = _HRESULT_TYPEDEF_((-2147463165))
E_ADS_UNKNOWN_OBJECT = _HRESULT_TYPEDEF_((-2147463164))
E_ADS_PROPERTY_NOT_SET = _HRESULT_TYPEDEF_((-2147463163))
E_ADS_PROPERTY_NOT_SUPPORTED = _HRESULT_TYPEDEF_((-2147463162))
E_ADS_PROPERTY_INVALID = _HRESULT_TYPEDEF_((-2147463161))
E_ADS_BAD_PARAMETER = _HRESULT_TYPEDEF_((-2147463160))
E_ADS_OBJECT_UNBOUND = _HRESULT_TYPEDEF_((-2147463159))
E_ADS_PROPERTY_NOT_MODIFIED = _HRESULT_TYPEDEF_((-2147463158))
E_ADS_PROPERTY_MODIFIED = _HRESULT_TYPEDEF_((-2147463157))
E_ADS_CANT_CONVERT_DATATYPE = _HRESULT_TYPEDEF_((-2147463156))
E_ADS_PROPERTY_NOT_FOUND = _HRESULT_TYPEDEF_((-2147463155))
E_ADS_OBJECT_EXISTS = _HRESULT_TYPEDEF_((-2147463154))
E_ADS_SCHEMA_VIOLATION = _HRESULT_TYPEDEF_((-2147463153))
E_ADS_COLUMN_NOT_SET = _HRESULT_TYPEDEF_((-2147463152))
S_ADS_ERRORSOCCURRED = _HRESULT_TYPEDEF_(0x00005011)
S_ADS_NOMORE_ROWS = _HRESULT_TYPEDEF_(0x00005012)
S_ADS_NOMORE_COLUMNS = _HRESULT_TYPEDEF_(0x00005013)
E_ADS_INVALID_FILTER = _HRESULT_TYPEDEF_((-2147463148))
# ADS_DEREFENUM enum
ADS_DEREF_NEVER = 0
ADS_DEREF_SEARCHING = 1
ADS_DEREF_FINDING = 2
ADS_DEREF_ALWAYS = 3
# ADS_PREFERENCES_ENUM
ADSIPROP_ASYNCHRONOUS = 0
ADSIPROP_DEREF_ALIASES = 0x1
ADSIPROP_SIZE_LIMIT = 0x2
ADSIPROP_TIME_LIMIT = 0x3
ADSIPROP_ATTRIBTYPES_ONLY = 0x4
ADSIPROP_SEARCH_SCOPE = 0x5
ADSIPROP_TIMEOUT = 0x6
ADSIPROP_PAGESIZE = 0x7
ADSIPROP_PAGED_TIME_LIMIT = 0x8
ADSIPROP_CHASE_REFERRALS = 0x9
ADSIPROP_SORT_ON = 0xA
ADSIPROP_CACHE_RESULTS = 0xB
ADSIPROP_ADSIFLAG = 0xC
# ADSI_DIALECT_ENUM
ADSI_DIALECT_LDAP = 0
ADSI_DIALECT_SQL = 0x1
# ADS_CHASE_REFERRALS_ENUM
ADS_CHASE_REFERRALS_NEVER = 0
ADS_CHASE_REFERRALS_SUBORDINATE = 0x20
ADS_CHASE_REFERRALS_EXTERNAL = 0x40
ADS_CHASE_REFERRALS_ALWAYS = (
ADS_CHASE_REFERRALS_SUBORDINATE | ADS_CHASE_REFERRALS_EXTERNAL
)
# Generated by h2py from ObjSel.h
DSOP_SCOPE_TYPE_TARGET_COMPUTER = 0x00000001
DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN = 0x00000002
DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN = 0x00000004
DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN = 0x00000008
DSOP_SCOPE_TYPE_GLOBAL_CATALOG = 0x00000010
DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN = 0x00000020
DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN = 0x00000040
DSOP_SCOPE_TYPE_WORKGROUP = 0x00000080
DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE = 0x00000100
DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE = 0x00000200
DSOP_SCOPE_FLAG_STARTING_SCOPE = 0x00000001
DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT = 0x00000002
DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP = 0x00000004
DSOP_SCOPE_FLAG_WANT_PROVIDER_GC = 0x00000008
DSOP_SCOPE_FLAG_WANT_SID_PATH = 0x00000010
DSOP_SCOPE_FLAG_WANT_DOWNLEVEL_BUILTIN_PATH = 0x00000020
DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS = 0x00000040
DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS = 0x00000080
DSOP_SCOPE_FLAG_DEFAULT_FILTER_COMPUTERS = 0x00000100
DSOP_SCOPE_FLAG_DEFAULT_FILTER_CONTACTS = 0x00000200
DSOP_FILTER_INCLUDE_ADVANCED_VIEW = 0x00000001
DSOP_FILTER_USERS = 0x00000002
DSOP_FILTER_BUILTIN_GROUPS = 0x00000004
DSOP_FILTER_WELL_KNOWN_PRINCIPALS = 0x00000008
DSOP_FILTER_UNIVERSAL_GROUPS_DL = 0x00000010
DSOP_FILTER_UNIVERSAL_GROUPS_SE = 0x00000020
DSOP_FILTER_GLOBAL_GROUPS_DL = 0x00000040
DSOP_FILTER_GLOBAL_GROUPS_SE = 0x00000080
DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL = 0x00000100
DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE = 0x00000200
DSOP_FILTER_CONTACTS = 0x00000400
DSOP_FILTER_COMPUTERS = 0x00000800
DSOP_DOWNLEVEL_FILTER_USERS = -2147483647
DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS = -2147483646
DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS = -2147483644
DSOP_DOWNLEVEL_FILTER_COMPUTERS = -2147483640
DSOP_DOWNLEVEL_FILTER_WORLD = -2147483632
DSOP_DOWNLEVEL_FILTER_AUTHENTICATED_USER = -2147483616
DSOP_DOWNLEVEL_FILTER_ANONYMOUS = -2147483584
DSOP_DOWNLEVEL_FILTER_BATCH = -2147483520
DSOP_DOWNLEVEL_FILTER_CREATOR_OWNER = -2147483392
DSOP_DOWNLEVEL_FILTER_CREATOR_GROUP = -2147483136
DSOP_DOWNLEVEL_FILTER_DIALUP = -2147482624
DSOP_DOWNLEVEL_FILTER_INTERACTIVE = -2147481600
DSOP_DOWNLEVEL_FILTER_NETWORK = -2147479552
DSOP_DOWNLEVEL_FILTER_SERVICE = -2147475456
DSOP_DOWNLEVEL_FILTER_SYSTEM = -2147467264
DSOP_DOWNLEVEL_FILTER_EXCLUDE_BUILTIN_GROUPS = -2147450880
DSOP_DOWNLEVEL_FILTER_TERMINAL_SERVER = -2147418112
DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS = -2147352576
DSOP_DOWNLEVEL_FILTER_LOCAL_SERVICE = -2147221504
DSOP_DOWNLEVEL_FILTER_NETWORK_SERVICE = -2146959360
DSOP_DOWNLEVEL_FILTER_REMOTE_LOGON = -2146435072
DSOP_FLAG_MULTISELECT = 0x00000001
DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK = 0x00000002
CFSTR_DSOP_DS_SELECTION_LIST = "CFSTR_DSOP_DS_SELECTION_LIST"

View File

@ -0,0 +1,68 @@
# A demo for the IDsObjectPicker interface.
import win32clipboard
import pythoncom
from win32com.adsi import adsi
from win32com.adsi.adsicon import *
cf_objectpicker = win32clipboard.RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST)
def main():
hwnd = 0
# Create an instance of the object picker.
picker = pythoncom.CoCreateInstance(
adsi.CLSID_DsObjectPicker,
None,
pythoncom.CLSCTX_INPROC_SERVER,
adsi.IID_IDsObjectPicker,
)
# Create our scope init info.
siis = adsi.DSOP_SCOPE_INIT_INFOs(1)
sii = siis[0]
# Combine multiple scope types in a single array entry.
sii.type = (
DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN
)
# Set uplevel and downlevel filters to include only computer objects.
# Uplevel filters apply to both mixed and native modes.
# Notice that the uplevel and downlevel flags are different.
sii.filterFlags.uplevel.bothModes = DSOP_FILTER_COMPUTERS
sii.filterFlags.downlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS
# Initialize the interface.
picker.Initialize(
None, # Target is the local computer.
siis, # scope infos
DSOP_FLAG_MULTISELECT, # options
("objectGUID", "displayName"),
) # attributes to fetch
do = picker.InvokeDialog(hwnd)
# Extract the data from the IDataObject.
format_etc = (
cf_objectpicker,
None,
pythoncom.DVASPECT_CONTENT,
-1,
pythoncom.TYMED_HGLOBAL,
)
medium = do.GetData(format_etc)
data = adsi.StringAsDS_SELECTION_LIST(medium.data)
for item in data:
name, klass, adspath, upn, attrs, flags = item
print("Item", name)
print(" Class:", klass)
print(" AdsPath:", adspath)
print(" UPN:", upn)
print(" Attrs:", attrs)
print(" Flags:", flags)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,561 @@
"""A re-implementation of the MS DirectoryService samples related to services.
* Adds and removes an ActiveDirectory "Service Connection Point",
including managing the security on the object.
* Creates and registers Service Principal Names.
* Changes the username for a domain user.
Some of these functions are likely to become move to a module - but there
is also a little command-line-interface to try these functions out.
For example:
scp.py --account-name=domain\\user --service-class=PythonScpTest \\
--keyword=foo --keyword=bar --binding-string=bind_info \\
ScpCreate SpnCreate SpnRegister
would:
* Attempt to delete a Service Connection Point for the service class
'PythonScpTest'
* Attempt to create a Service Connection Point for that class, with 2
keywords and a binding string of 'bind_info'
* Create a Service Principal Name for the service and register it
to undo those changes, you could execute:
scp.py --account-name=domain\\user --service-class=PythonScpTest \\
SpnCreate SpnUnregister ScpDelete
which will:
* Create a SPN
* Unregister that SPN from the Active Directory.
* Delete the Service Connection Point
Executing with --test will create and remove one of everything.
"""
from win32com.adsi.adsicon import *
from win32com.adsi import adsi
import win32api, win32con, winerror
from win32com.client import Dispatch
import ntsecuritycon as dscon
import win32security
import optparse, textwrap
import traceback
verbose = 1
g_createdSCP = None
g_createdSPNs = []
g_createdSPNLast = None
import logging
logger = logging # use logging module global methods for now.
# still a bit confused about log(n, ...) vs logger.info/debug()
# Returns distinguished name of SCP.
def ScpCreate(
service_binding_info,
service_class_name, # Service class string to store in SCP.
account_name=None, # Logon account that needs access to SCP.
container_name=None,
keywords=None,
object_class="serviceConnectionPoint",
dns_name_type="A",
dn=None,
dns_name=None,
):
container_name = container_name or service_class_name
if not dns_name:
# Get the DNS name of the local computer
dns_name = win32api.GetComputerNameEx(win32con.ComputerNameDnsFullyQualified)
# Get the distinguished name of the computer object for the local computer
if dn is None:
dn = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
# Compose the ADSpath and bind to the computer object for the local computer
comp = adsi.ADsGetObject("LDAP://" + dn, adsi.IID_IDirectoryObject)
# Publish the SCP as a child of the computer object
keywords = keywords or []
# Fill in the attribute values to be stored in the SCP.
attrs = [
("cn", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (container_name,)),
("objectClass", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (object_class,)),
("keywords", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, keywords),
("serviceDnsName", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, (dns_name,)),
(
"serviceDnsNameType",
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
(dns_name_type,),
),
(
"serviceClassName",
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
(service_class_name,),
),
(
"serviceBindingInformation",
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
(service_binding_info,),
),
]
new = comp.CreateDSObject("cn=" + container_name, attrs)
logger.info("New connection point is at %s", container_name)
# Wrap in a usable IDispatch object.
new = Dispatch(new)
# And allow access to the SCP for the specified account name
AllowAccessToScpProperties(account_name, new)
return new
def ScpDelete(container_name, dn=None):
if dn is None:
dn = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
logger.debug("Removing connection point '%s' from %s", container_name, dn)
# Compose the ADSpath and bind to the computer object for the local computer
comp = adsi.ADsGetObject("LDAP://" + dn, adsi.IID_IDirectoryObject)
comp.DeleteDSObject("cn=" + container_name)
logger.info("Deleted service connection point '%s'", container_name)
# This function is described in detail in the MSDN article titled
# "Enabling Service Account to Access SCP Properties"
# From that article:
# The following sample code sets a pair of ACEs on a service connection point
# (SCP) object. The ACEs grant read/write access to the user or computer account
# under which the service instance will be running. Your service installation
# program calls this code to ensure that the service will be allowed to update
# its properties at run time. If you don't set ACEs like these, your service
# will get access-denied errors if it tries to modify the SCP's properties.
#
# The code uses the IADsSecurityDescriptor, IADsAccessControlList, and
# IADsAccessControlEntry interfaces to do the following:
# * Get the SCP object's security descriptor.
# * Set ACEs in the DACL of the security descriptor.
# * Set the security descriptor back on the SCP object.
def AllowAccessToScpProperties(
accountSAM, # Service account to allow access.
scpObject, # The IADs SCP object.
schemaIDGUIDs=( # Attributes to allow write-access to.
"{28630eb8-41d5-11d1-a9c1-0000f80367c1}", # serviceDNSName
"{b7b1311c-b82e-11d0-afee-0000f80367c1}", # serviceBindingInformation
),
):
# If no service account is specified, service runs under LocalSystem.
# So allow access to the computer account of the service's host.
if accountSAM:
trustee = accountSAM
else:
# Get the SAM account name of the computer object for the server.
trustee = win32api.GetComputerObjectName(win32con.NameSamCompatible)
# Get the nTSecurityDescriptor attribute
attribute = "nTSecurityDescriptor"
sd = getattr(scpObject, attribute)
acl = sd.DiscretionaryAcl
for sguid in schemaIDGUIDs:
ace = Dispatch(adsi.CLSID_AccessControlEntry)
# Set the properties of the ACE.
# Allow read and write access to the property.
ace.AccessMask = ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_DS_WRITE_PROP
# Set the trustee, which is either the service account or the
# host computer account.
ace.Trustee = trustee
# Set the ACE type.
ace.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
# Set AceFlags to zero because ACE is not inheritable.
ace.AceFlags = 0
# Set Flags to indicate an ACE that protects a specified object.
ace.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
# Set ObjectType to the schemaIDGUID of the attribute.
ace.ObjectType = sguid
# Add the ACEs to the DACL.
acl.AddAce(ace)
# Write the modified DACL back to the security descriptor.
sd.DiscretionaryAcl = acl
# Write the ntSecurityDescriptor property to the property cache.
setattr(scpObject, attribute, sd)
# SetInfo updates the SCP object in the directory.
scpObject.SetInfo()
logger.info("Set security on object for account '%s'" % (trustee,))
# Service Principal Names functions from the same sample.
# The example calls the DsWriteAccountSpn function, which stores the SPNs in
# Microsoft Active Directory under the servicePrincipalName attribute of the
# account object specified by the serviceAcctDN parameter. The account object
# corresponds to the logon account specified in the CreateService call for this
# service instance. If the logon account is a domain user account,
# serviceAcctDN must be the distinguished name of the account object in
# Active Directory for that user account. If the service's logon account is the
# LocalSystem account, serviceAcctDN must be the distinguished name of the
# computer account object for the host computer on which the service is
# installed. win32api.TranslateNames and win32security.DsCrackNames can
# be used to convert a domain\account format name to a distinguished name.
def SpnRegister(
serviceAcctDN, # DN of the service's logon account
spns, # List of SPNs to register
operation, # Add, replace, or delete SPNs
):
assert type(spns) not in [str, str] and hasattr(spns, "__iter__"), (
"spns must be a sequence of strings (got %r)" % spns
)
# Bind to a domain controller.
# Get the domain for the current user.
samName = win32api.GetUserNameEx(win32api.NameSamCompatible)
samName = samName.split("\\", 1)[0]
if not serviceAcctDN:
# Get the SAM account name of the computer object for the server.
serviceAcctDN = win32api.GetComputerObjectName(win32con.NameFullyQualifiedDN)
logger.debug("SpnRegister using DN '%s'", serviceAcctDN)
# Get the name of a domain controller in that domain.
info = win32security.DsGetDcName(
domainName=samName,
flags=dscon.DS_IS_FLAT_NAME
| dscon.DS_RETURN_DNS_NAME
| dscon.DS_DIRECTORY_SERVICE_REQUIRED,
)
# Bind to the domain controller.
handle = win32security.DsBind(info["DomainControllerName"])
# Write the SPNs to the service account or computer account.
logger.debug("DsWriteAccountSpn with spns %s")
win32security.DsWriteAccountSpn(
handle, # handle to the directory
operation, # Add or remove SPN from account's existing SPNs
serviceAcctDN, # DN of service account or computer account
spns,
) # names
# Unbind the DS in any case (but Python would do it anyway)
handle.Close()
def UserChangePassword(username_dn, new_password):
# set the password on the account.
# Use the distinguished name to bind to the account object.
accountPath = "LDAP://" + username_dn
user = adsi.ADsGetObject(accountPath, adsi.IID_IADsUser)
# Set the password on the account.
user.SetPassword(new_password)
# functions related to the command-line interface
def log(level, msg, *args):
if verbose >= level:
print(msg % args)
class _NoDefault:
pass
def _get_option(po, opt_name, default=_NoDefault):
parser, options = po
ret = getattr(options, opt_name, default)
if not ret and default is _NoDefault:
parser.error("The '%s' option must be specified for this operation" % opt_name)
if not ret:
ret = default
return ret
def _option_error(po, why):
parser = po[0]
parser.error(why)
def do_ScpCreate(po):
"""Create a Service Connection Point"""
global g_createdSCP
scp = ScpCreate(
_get_option(po, "binding_string"),
_get_option(po, "service_class"),
_get_option(po, "account_name_sam", None),
keywords=_get_option(po, "keywords", None),
)
g_createdSCP = scp
return scp.distinguishedName
def do_ScpDelete(po):
"""Delete a Service Connection Point"""
sc = _get_option(po, "service_class")
try:
ScpDelete(sc)
except adsi.error as details:
if details[0] != winerror.ERROR_DS_OBJ_NOT_FOUND:
raise
log(2, "ScpDelete ignoring ERROR_DS_OBJ_NOT_FOUND for service-class '%s'", sc)
return sc
def do_SpnCreate(po):
"""Create a Service Principal Name"""
# The 'service name' is the dn of our scp.
if g_createdSCP is None:
# Could accept an arg to avoid this?
_option_error(po, "ScpCreate must have been specified before SpnCreate")
# Create a Service Principal Name"
spns = win32security.DsGetSpn(
dscon.DS_SPN_SERVICE,
_get_option(po, "service_class"),
g_createdSCP.distinguishedName,
_get_option(po, "port", 0),
None,
None,
)
spn = spns[0]
log(2, "Created SPN: %s", spn)
global g_createdSPNLast
g_createdSPNLast = spn
g_createdSPNs.append(spn)
return spn
def do_SpnRegister(po):
"""Register a previously created Service Principal Name"""
if not g_createdSPNLast:
_option_error(po, "SpnCreate must appear before SpnRegister")
SpnRegister(
_get_option(po, "account_name_dn", None),
(g_createdSPNLast,),
dscon.DS_SPN_ADD_SPN_OP,
)
return g_createdSPNLast
def do_SpnUnregister(po):
"""Unregister a previously created Service Principal Name"""
if not g_createdSPNLast:
_option_error(po, "SpnCreate must appear before SpnUnregister")
SpnRegister(
_get_option(po, "account_name_dn", None),
(g_createdSPNLast,),
dscon.DS_SPN_DELETE_SPN_OP,
)
return g_createdSPNLast
def do_UserChangePassword(po):
"""Change the password for a specified user"""
UserChangePassword(_get_option(po, "account_name_dn"), _get_option(po, "password"))
return "Password changed OK"
handlers = (
("ScpCreate", do_ScpCreate),
("ScpDelete", do_ScpDelete),
("SpnCreate", do_SpnCreate),
("SpnRegister", do_SpnRegister),
("SpnUnregister", do_SpnUnregister),
("UserChangePassword", do_UserChangePassword),
)
class HelpFormatter(optparse.IndentedHelpFormatter):
def format_description(self, description):
return description
def main():
global verbose
_handlers_dict = {}
arg_descs = []
for arg, func in handlers:
this_desc = "\n".join(textwrap.wrap(func.__doc__, subsequent_indent=" " * 8))
arg_descs.append(" %s: %s" % (arg, this_desc))
_handlers_dict[arg.lower()] = func
description = __doc__ + "\ncommands:\n" + "\n".join(arg_descs) + "\n"
parser = optparse.OptionParser(
usage="%prog [options] command ...",
description=description,
formatter=HelpFormatter(),
)
parser.add_option(
"-v",
action="count",
dest="verbose",
default=1,
help="increase the verbosity of status messages",
)
parser.add_option(
"-q", "--quiet", action="store_true", help="Don't print any status messages"
)
parser.add_option(
"-t",
"--test",
action="store_true",
help="Execute a mini-test suite, providing defaults for most options and args",
),
parser.add_option(
"",
"--show-tracebacks",
action="store_true",
help="Show the tracebacks for any exceptions",
)
parser.add_option("", "--service-class", help="The service class name to use")
parser.add_option(
"", "--port", default=0, help="The port number to associate with the SPN"
)
parser.add_option(
"", "--binding-string", help="The binding string to use for SCP creation"
)
parser.add_option(
"", "--account-name", help="The account name to use (default is LocalSystem)"
)
parser.add_option("", "--password", help="The password to set.")
parser.add_option(
"",
"--keyword",
action="append",
dest="keywords",
help="""A keyword to add to the SCP. May be specified
multiple times""",
)
parser.add_option(
"",
"--log-level",
help="""The log-level to use - may be a number or a logging
module constant""",
default=str(logging.WARNING),
)
options, args = parser.parse_args()
po = (parser, options)
# fixup misc
try:
options.port = int(options.port)
except (TypeError, ValueError):
parser.error("--port must be numeric")
# fixup log-level
try:
log_level = int(options.log_level)
except (TypeError, ValueError):
try:
log_level = int(getattr(logging, options.log_level.upper()))
except (ValueError, TypeError, AttributeError):
parser.error("Invalid --log-level value")
try:
sl = logger.setLevel
# logger is a real logger
except AttributeError:
# logger is logging module
sl = logging.getLogger().setLevel
sl(log_level)
# Check -q/-v
if options.quiet and options.verbose:
parser.error("Can't specify --quiet and --verbose")
if options.quiet:
options.verbose -= 1
verbose = options.verbose
# --test
if options.test:
if args:
parser.error("Can't specify args with --test")
args = "ScpDelete ScpCreate SpnCreate SpnRegister SpnUnregister ScpDelete"
log(1, "--test - pretending args are:\n %s", args)
args = args.split()
if not options.service_class:
options.service_class = "PythonScpTest"
log(2, "--test: --service-class=%s", options.service_class)
if not options.keywords:
options.keywords = "Python Powered".split()
log(2, "--test: --keyword=%s", options.keywords)
if not options.binding_string:
options.binding_string = "test binding string"
log(2, "--test: --binding-string=%s", options.binding_string)
# check args
if not args:
parser.error("No command specified (use --help for valid commands)")
for arg in args:
if arg.lower() not in _handlers_dict:
parser.error("Invalid command '%s' (use --help for valid commands)" % arg)
# Patch up account-name.
if options.account_name:
log(2, "Translating account name '%s'", options.account_name)
options.account_name_sam = win32security.TranslateName(
options.account_name, win32api.NameUnknown, win32api.NameSamCompatible
)
log(2, "NameSamCompatible is '%s'", options.account_name_sam)
options.account_name_dn = win32security.TranslateName(
options.account_name, win32api.NameUnknown, win32api.NameFullyQualifiedDN
)
log(2, "NameFullyQualifiedDNis '%s'", options.account_name_dn)
# do it.
for arg in args:
handler = _handlers_dict[arg.lower()] # already been validated
if handler is None:
parser.error("Invalid command '%s'" % arg)
err_msg = None
try:
try:
log(2, "Executing '%s'...", arg)
result = handler(po)
log(1, "%s: %s", arg, result)
except:
if options.show_tracebacks:
print("--show-tracebacks specified - dumping exception")
traceback.print_exc()
raise
except adsi.error as xxx_todo_changeme:
(hr, desc, exc, argerr) = xxx_todo_changeme.args
if exc:
extra_desc = exc[2]
else:
extra_desc = ""
err_msg = desc
if extra_desc:
err_msg += "\n\t" + extra_desc
except win32api.error as xxx_todo_changeme1:
(hr, func, msg) = xxx_todo_changeme1.args
err_msg = msg
if err_msg:
log(1, "Command '%s' failed: %s", arg, err_msg)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("*** Interrupted")

View File

@ -0,0 +1,151 @@
from win32com.adsi import adsi
from win32com.adsi.adsicon import *
from win32com.adsi import adsicon
import pythoncom, pywintypes, win32security
options = None # set to optparse options object
ADsTypeNameMap = {}
def getADsTypeName(type_val):
# convert integer type to the 'typename' as known in the headerfiles.
if not ADsTypeNameMap:
for n, v in adsicon.__dict__.items():
if n.startswith("ADSTYPE_"):
ADsTypeNameMap[v] = n
return ADsTypeNameMap.get(type_val, hex(type_val))
def _guid_from_buffer(b):
return pywintypes.IID(b, True)
def _sid_from_buffer(b):
return str(pywintypes.SID(b))
_null_converter = lambda x: x
converters = {
"objectGUID": _guid_from_buffer,
"objectSid": _sid_from_buffer,
"instanceType": getADsTypeName,
}
def log(level, msg, *args):
if options.verbose >= level:
print("log:", msg % args)
def getGC():
cont = adsi.ADsOpenObject(
"GC:", options.user, options.password, 0, adsi.IID_IADsContainer
)
enum = adsi.ADsBuildEnumerator(cont)
# Only 1 child of the global catalog.
for e in enum:
gc = e.QueryInterface(adsi.IID_IDirectorySearch)
return gc
return None
def print_attribute(col_data):
prop_name, prop_type, values = col_data
if values is not None:
log(2, "property '%s' has type '%s'", prop_name, getADsTypeName(prop_type))
value = [converters.get(prop_name, _null_converter)(v[0]) for v in values]
if len(value) == 1:
value = value[0]
print(" %s=%r" % (prop_name, value))
else:
print(" %s is None" % (prop_name,))
def search():
gc = getGC()
if gc is None:
log(0, "Can't find the global catalog")
return
prefs = [(ADS_SEARCHPREF_SEARCH_SCOPE, (ADS_SCOPE_SUBTREE,))]
hr, statuses = gc.SetSearchPreference(prefs)
log(3, "SetSearchPreference returned %d/%r", hr, statuses)
if options.attributes:
attributes = options.attributes.split(",")
else:
attributes = None
h = gc.ExecuteSearch(options.filter, attributes)
hr = gc.GetNextRow(h)
while hr != S_ADS_NOMORE_ROWS:
print("-- new row --")
if attributes is None:
# Loop over all columns returned
while 1:
col_name = gc.GetNextColumnName(h)
if col_name is None:
break
data = gc.GetColumn(h, col_name)
print_attribute(data)
else:
# loop over attributes specified.
for a in attributes:
try:
data = gc.GetColumn(h, a)
print_attribute(data)
except adsi.error as details:
if details[0] != E_ADS_COLUMN_NOT_SET:
raise
print_attribute((a, None, None))
hr = gc.GetNextRow(h)
gc.CloseSearchHandle(h)
def main():
global options
from optparse import OptionParser
parser = OptionParser()
parser.add_option(
"-f", "--file", dest="filename", help="write report to FILE", metavar="FILE"
)
parser.add_option(
"-v",
"--verbose",
action="count",
default=1,
help="increase verbosity of output",
)
parser.add_option(
"-q", "--quiet", action="store_true", help="suppress output messages"
)
parser.add_option("-U", "--user", help="specify the username used to connect")
parser.add_option("-P", "--password", help="specify the password used to connect")
parser.add_option(
"",
"--filter",
default="(&(objectCategory=person)(objectClass=User))",
help="specify the search filter",
)
parser.add_option(
"", "--attributes", help="comma sep'd list of attribute names to print"
)
options, args = parser.parse_args()
if options.quiet:
if options.verbose != 1:
parser.error("Can not use '--verbose' and '--quiet'")
options.verbose = 0
if args:
parser.error("You need not specify args")
search()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,271 @@
import sys, string
import pythoncom
import win32api
from win32com.adsi import *
verbose_level = 0
server = "" # Must have trailing /
local_name = win32api.GetComputerName()
def DumpRoot():
"Dumps the root DSE"
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
for item in rootdse.Get("SupportedLDAPVersion"):
print("%s supports ldap version %s" % (path, item))
attributes = ["CurrentTime", "defaultNamingContext"]
for attr in attributes:
val = rootdse.Get(attr)
print(" %s=%s" % (attr, val))
###############################################
#
# Code taken from article titled:
# Reading attributeSchema and classSchema Objects
def _DumpClass(child):
attrs = "Abstract lDAPDisplayName schemaIDGUID schemaNamingContext attributeSyntax oMSyntax"
_DumpTheseAttributes(child, string.split(attrs))
def _DumpAttribute(child):
attrs = "lDAPDisplayName schemaIDGUID adminDescription adminDisplayName rDNAttID defaultHidingValue defaultObjectCategory systemOnly defaultSecurityDescriptor"
_DumpTheseAttributes(child, string.split(attrs))
def _DumpTheseAttributes(child, attrs):
for attr in attrs:
try:
val = child.Get(attr)
except pythoncom.com_error as details:
continue
# ###
(hr, msg, exc, arg) = details
if exc and exc[2]:
msg = exc[2]
val = "<Error: %s>" % (msg,)
if verbose_level >= 2:
print(" %s: %s=%s" % (child.Class, attr, val))
def DumpSchema():
"Dumps the default DSE schema"
# Bind to rootDSE to get the schemaNamingContext property.
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
name = rootdse.Get("schemaNamingContext")
# Bind to the actual schema container.
path = "LDAP://" + server + name
print("Binding to", path)
ob = ADsGetObject(path)
nclasses = nattr = nsub = nunk = 0
# Enumerate the attribute and class objects in the schema container.
for child in ob:
# Find out if this is a class, attribute, or subSchema object.
class_name = child.Class
if class_name == "classSchema":
_DumpClass(child)
nclasses = nclasses + 1
elif class_name == "attributeSchema":
_DumpAttribute(child)
nattr = nattr + 1
elif class_name == "subSchema":
nsub = nsub + 1
else:
print("Unknown class:", class_name)
nunk = nunk + 1
if verbose_level:
print("Processed", nclasses, "classes")
print("Processed", nattr, "attributes")
print("Processed", nsub, "sub-schema's")
print("Processed", nunk, "unknown types")
def _DumpObject(ob, level=0):
prefix = " " * level
print("%s%s object: %s" % (prefix, ob.Class, ob.Name))
# Do the directory object thing
try:
dir_ob = ADsGetObject(ob.ADsPath, IID_IDirectoryObject)
except pythoncom.com_error:
dir_ob = None
if dir_ob is not None:
info = dir_ob.GetObjectInformation()
print("%s RDN='%s', ObjectDN='%s'" % (prefix, info.RDN, info.ObjectDN))
# Create a list of names to fetch
names = ["distinguishedName"]
attrs = dir_ob.GetObjectAttributes(names)
for attr in attrs:
for val, typ in attr.Values:
print("%s Attribute '%s' = %s" % (prefix, attr.AttrName, val))
for child in ob:
_DumpObject(child, level + 1)
def DumpAllObjects():
"Recursively dump the entire directory!"
path = "LDAP://%srootDSE" % server
rootdse = ADsGetObject(path)
name = rootdse.Get("defaultNamingContext")
# Bind to the actual schema container.
path = "LDAP://" + server + name
print("Binding to", path)
ob = ADsGetObject(path)
# Enumerate the attribute and class objects in the schema container.
_DumpObject(ob)
##########################################################
#
# Code taken from article:
# Example Code for Enumerating Schema Classes, Attributes, and Syntaxes
# Fill a map with VT_ datatypes, to give us better names:
vt_map = {}
for name, val in pythoncom.__dict__.items():
if name[:3] == "VT_":
vt_map[val] = name
def DumpSchema2():
"Dumps the schema using an alternative technique"
path = "LDAP://%sschema" % (server,)
schema = ADsGetObject(path, IID_IADsContainer)
nclass = nprop = nsyntax = 0
for item in schema:
item_class = string.lower(item.Class)
if item_class == "class":
items = []
if item.Abstract:
items.append("Abstract")
if item.Auxiliary:
items.append("Auxiliary")
# if item.Structural: items.append("Structural")
desc = string.join(items, ", ")
import win32com.util
iid_name = win32com.util.IIDToInterfaceName(item.PrimaryInterface)
if verbose_level >= 2:
print(
"Class: Name=%s, Flags=%s, Primary Interface=%s"
% (item.Name, desc, iid_name)
)
nclass = nclass + 1
elif item_class == "property":
if item.MultiValued:
val_type = "Multi-Valued"
else:
val_type = "Single-Valued"
if verbose_level >= 2:
print("Property: Name=%s, %s" % (item.Name, val_type))
nprop = nprop + 1
elif item_class == "syntax":
data_type = vt_map.get(item.OleAutoDataType, "<unknown type>")
if verbose_level >= 2:
print("Syntax: Name=%s, Datatype = %s" % (item.Name, data_type))
nsyntax = nsyntax + 1
if verbose_level >= 1:
print("Processed", nclass, "classes")
print("Processed", nprop, "properties")
print("Processed", nsyntax, "syntax items")
def DumpGC():
"Dumps the GC: object (whatever that is!)"
ob = ADsGetObject("GC:", IID_IADsContainer)
for sub_ob in ob:
print("GC ob: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
def DumpLocalUsers():
"Dumps the local machine users"
path = "WinNT://%s,computer" % (local_name,)
ob = ADsGetObject(path, IID_IADsContainer)
ob.put_Filter(["User", "Group"])
for sub_ob in ob:
print("User/Group: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
def DumpLocalGroups():
"Dumps the local machine groups"
path = "WinNT://%s,computer" % (local_name,)
ob = ADsGetObject(path, IID_IADsContainer)
ob.put_Filter(["Group"])
for sub_ob in ob:
print("Group: %s (%s)" % (sub_ob.Name, sub_ob.ADsPath))
# get the members
members = sub_ob.Members()
for member in members:
print(" Group member: %s (%s)" % (member.Name, member.ADsPath))
def usage(tests):
import os
print("Usage: %s [-s server ] [-v] [Test ...]" % os.path.basename(sys.argv[0]))
print(" -v : Verbose - print more information")
print(" -s : server - execute the tests against the named server")
print("where Test is one of:")
for t in tests:
print(t.__name__, ":", t.__doc__)
print()
print("If not tests are specified, all tests are run")
sys.exit(1)
def main():
import getopt, traceback
tests = []
for ob in globals().values():
if type(ob) == type(main) and ob.__doc__:
tests.append(ob)
opts, args = getopt.getopt(sys.argv[1:], "s:hv")
for opt, val in opts:
if opt == "-s":
if val[-1] not in "\\/":
val = val + "/"
global server
server = val
if opt == "-h":
usage(tests)
if opt == "-v":
global verbose_level
verbose_level = verbose_level + 1
if len(args) == 0:
print("Running all tests - use '-h' to see command-line options...")
dotests = tests
else:
dotests = []
for arg in args:
for t in tests:
if t.__name__ == arg:
dotests.append(t)
break
else:
print("Test '%s' unknown - skipping" % arg)
if not len(dotests):
print("Nothing to do!")
usage(tests)
for test in dotests:
try:
test()
except:
print("Test %s failed" % test.__name__)
traceback.print_exc()
if __name__ == "__main__":
main()