Spaces:
Running
Running
import pythoncom | |
import pywintypes | |
import win32security | |
from win32com.adsi import adsi, adsicon | |
from win32com.adsi.adsicon import * | |
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() | |